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