From 30b598c7d885b79e792232eff7146b524e31493b Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 1 Nov 2026 09:51:05 +0800 Subject: mac: sync vimrc and tmux.conf from current host --- mac/tmux.conf | 5 ++ mac/vimrc | 155 ++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 113 insertions(+), 47 deletions(-) (limited to 'mac') diff --git a/mac/tmux.conf b/mac/tmux.conf index 5afc0b5..bd89157 100644 --- a/mac/tmux.conf +++ b/mac/tmux.conf @@ -1,3 +1,8 @@ +# Ctrl-b f: prompt for text, list windows whose name, pane title or pane contents match; Enter jumps +# Ctrl-b w: tree of every window in every session; press f inside it to filter by name, Enter jumps +# Ctrl-b s: tree of sessions (same tree, session view) +# Ctrl-b p: go to the previous window (lower index, wraps); Ctrl-b n goes to the next one +# # Vi mode for copy setw -g mode-keys vi diff --git a/mac/vimrc b/mac/vimrc index 6de4092..ba9bd88 100644 --- a/mac/vimrc +++ b/mac/vimrc @@ -1,4 +1,14 @@ -" ~/.vimrc (macOS + Linux) — self-contained; source of truth: dev_env/mac/vimrc +" /etc/vim/vimrc — self-contained; source of truth: /v1/dev_env/core/vim.sh +" gt: go to next tab (right, wraps) +" gT: go to previous tab (left, wraps) +" 2gt: go to tab number 2 (counted from 1 at the left) +" :q: close the current window, and the tab too if it was the last window in it +" ZZ: save if changed, then close the window (and the tab if it was the last window in it) +" ZQ: close the window WITHOUT saving (like :q!), and the tab too if it was the last window in it +" g: jump to the last-accessed tab (press g, release, then Tab); toggles between two tabs +" Ctrl-w w: cycle windows in this tab, e.g. into and out of the K popup (Ctrl-w p toggles back) +" 7G12|: go to line 7, column 12 (normal-mode keys, no colon; 3w moves 3 words) +" Reset an edited cargo dependency: delete ~/.cargo/registry/src//-/ then run cargo fetch " " Setup (LSP servers below are optional — each is guarded by executable()): " plugins: curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ @@ -6,16 +16,39 @@ " 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 +" uv tool install ruff && uv tool install pyright " " 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 +" ===== Shortcuts: one line each, = \ (comment follows the |) ===== +inoremap | " insert Ctrl-a: jump to line start +inoremap | " insert Ctrl-e: jump to line end +inoremap pumvisible() ? "\" : asyncomplete#force_refresh()| " insert Ctrl-l: toggle completion menu +inoremap pumvisible() ? "\" : "\"| " in menu Tab: next item +inoremap pumvisible() ? "\" : "\"| " in menu Shift-Tab: previous item +inoremap pumvisible() ? "\" : "\"| " in menu Enter: accept item +nnoremap 0| " Ctrl-a: jump to line start +nnoremap $| " Ctrl-e: jump to line end +nnoremap :nohlsearch| " Ctrl-l: clear search highlight +nnoremap :Files| " Ctrl-p: fuzzy-find a file +nnoremap rg :Rg| " \rg: search text in project +nnoremap b :Buffers| " \b: list open buffers +nnoremap n :NERDTreeToggle| " \n: toggle file tree +nnoremap gd :call GotoDef()| " gd: go to definition (Ctrl-o back) +nnoremap gi :LspImplementation| " gi: go to implementation +nnoremap gy :tab LspTypeDefinition| " gy: go to type definition in a new tab (e -> struct DirEntry) +nnoremap k :call ToggleHover()| " \k: toggle hover docs +nnoremap K :call ToggleHover()| " K: toggle hover docs (same as \k) +nnoremap D :LspDocumentation| " \D: show documentation +nnoremap e :call ToggleDiagnostic()| " \e: show error on this line +nnoremap l :lopen| " \l: list all errors +nnoremap a :LspCodeAction| " \a: code actions popup +nnoremap rn :LspRename| " \rn: rename symbol +nnoremap f :LspDocumentFormat| " \f: format file +nnoremap em :call ExpandMacro()| " \em: expand macro under cursor augroup netcat_clipboard @@ -47,6 +80,7 @@ set statusline=%F set wildmenu set splitright set splitbelow +set hidden " gd/LSP jumps reuse the window even with unsaved changes set noswapfile set regexpengine=2 set completeopt=menu,menuone,noinsert,noselect @@ -73,11 +107,24 @@ colorscheme zellner autocmd InsertLeave * silent! update -inoremap -inoremap -nnoremap 0 -nnoremap $ -nnoremap :nohlsearch +" Files rustup and cargo manage (toolchains, downloaded crates) open locked; :setl ma noro to override +function! s:LockIfManaged() abort + if !exists('s:managed') + let l:cargo = empty($CARGO_HOME) ? expand('~/.cargo') : $CARGO_HOME + let s:managed = [trim(system('rustup show home')), l:cargo . '/registry', l:cargo . '/git'] + endif + for l:dir in s:managed + if stridx(expand('%:p'), l:dir . '/') == 0 + setlocal readonly nomodifiable + return + endif + endfor +endfunction +augroup managed_readonly + autocmd! + autocmd BufReadPost * call s:LockIfManaged() +augroup END + call plug#begin('~/.vim/plugged') Plug 'prabirshrestha/async.vim' @@ -97,10 +144,6 @@ 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')) @@ -118,24 +161,6 @@ if executable(expand('~/.cargo/bin/rust-analyzer')) \ }, \ }) 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', @@ -155,6 +180,23 @@ if executable(expand('~/.local/bin/ty')) && executable(s:uv_bin) \ 'allowlist': ['python'], \ }) endif +" tofu-ls (OpenTofu/Terraform .tf) for go-to-definition +if executable(expand('~/.local/bin/tofu-ls')) + au User lsp_setup call lsp#register_server({ + \ 'name': 'tofu-ls', + \ 'cmd': {server_info -> [expand('~/.local/bin/tofu-ls'), 'serve']}, + \ 'allowlist': ['terraform', 'terraform-vars'], + \ }) +endif +" gopls (Go) for go-to-definition +if executable(expand('~/go/bin/gopls')) + au User lsp_setup call lsp#register_server({ + \ 'name': 'gopls', + \ 'cmd': {server_info -> [expand('~/go/bin/gopls')]}, + \ 'allowlist': ['go'], + \ 'root_uri': {server_info -> lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'go.mod'))}, + \ }) +endif " Force per-keystroke LSP sync for Python (vim-lsp only syncs on " InsertLeave/TextChanged by default, not while actively typing). @@ -167,6 +209,7 @@ 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_code_action_ui = 'float' " \a = one popup menu, not 3 windows let g:lsp_signature_help_enabled = 0 function! s:set_preview_height() abort @@ -208,15 +251,6 @@ function! ToggleDiagnostic() abort 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 @@ -247,11 +281,38 @@ function! s:expand_macro_handler(data) abort call append(line('$'), split(l:result['expansion'], "\n")) endfunction -nnoremap em :call ExpandMacro() -inoremap -inoremap -inoremap pumvisible() ? "\" : "\" -inoremap pumvisible() ? "\" : "\" -inoremap pumvisible() ? "\" : "\" +" gd: say when rust-analyzer is still starting/indexing instead of a false "No definition found" +let g:lsp_work_done_progress_enabled = 1 +function! s:GotoDef() abort + if &filetype ==# 'rust' + let l:st = lsp#get_server_status('rust-analyzer') + if l:st !=# 'running' + echo 'rust-analyzer ' . l:st . ', try again in a few seconds' + return + endif + let l:busy = filter(copy(lsp#get_progress()), + \ {_, p -> p['server'] ==# 'rust-analyzer' && get(p, 'title', '') !~? 'check'}) + if !empty(l:busy) + echo 'rust-analyzer still indexing: ' . get(l:busy[0], 'title', '') . ' ' . get(l:busy[0], 'message', '') + return + endif + endif + tab LspDefinition +endfunction +" Numbered tab labels (1:main.rs 2:fs.rs): the number is what Ngt jumps to. +function! TabLine() abort + let l:s = '' + for l:i in range(1, tabpagenr('$')) + let l:buf = tabpagebuflist(l:i)[tabpagewinnr(l:i) - 1] + let l:name = fnamemodify(bufname(l:buf), ':t') + if l:name ==# '' + let l:name = '[No Name]' + endif + let l:hl = l:i == tabpagenr() ? '%#TabLineSel#' : '%#TabLine#' + let l:s .= l:hl . ' ' . l:i . ':' . l:name . ' ' + endfor + return l:s . '%#TabLineFill#' +endfunction +set tabline=%!TabLine() -- cgit