.vimrc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. " Plugin manager
  2. if empty(glob('~/.vim/autoload/plug.vim'))
  3. silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
  4. \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  5. autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
  6. endif
  7. " Plugins
  8. call plug#begin('~/.vim/plugged')
  9. Plug 'preservim/nerdtree'
  10. Plug 'tpope/vim-fugitive'
  11. Plug 'tpope/vim-commentary'
  12. Plug 'junegunn/vim-peekaboo'
  13. Plug 'itchyny/lightline.vim'
  14. Plug 'dikiaap/minimalist'
  15. Plug 'kaicataldo/material.vim'
  16. " Plug 'dense-analysis/ale'
  17. Plug 'ssh://git@gogs.viktorgrahn.com:2022/viktor/ale.git'
  18. Plug 'maximbaz/lightline-ale'
  19. Plug 'preservim/tagbar'
  20. Plug 'vim-php/tagbar-phpctags.vim'
  21. Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  22. Plug 'junegunn/fzf.vim'
  23. Plug 'airblade/vim-gitgutter'
  24. Plug 'mxw/vim-jsx'
  25. Plug 'pangloss/vim-javascript'
  26. Plug 'natebosch/vim-lsc'
  27. Plug 'tpope/vim-surround'
  28. Plug 'nordtheme/vim'
  29. Plug 'ap/vim-css-color', { 'for': [ 'css', 'scss' ] }
  30. call plug#end()
  31. filetype plugin indent on
  32. syntax on
  33. set autoindent
  34. set backspace=2
  35. set background=dark
  36. set completeopt=menu,popup,noselect
  37. set cursorcolumn
  38. set cursorline
  39. set expandtab
  40. set history=1000
  41. set hlsearch
  42. set incsearch
  43. set nowrap
  44. set number
  45. set numberwidth=4
  46. set pastetoggle=<F12> "Press <F12> when paste-alot
  47. set preserveindent
  48. set ruler
  49. set shiftround
  50. set shiftwidth=2
  51. set shortmess=atI
  52. set showcmd
  53. set showmatch
  54. set smartindent
  55. set smarttab
  56. set splitright
  57. set switchbuf+=usetab,newtab
  58. set termguicolors
  59. set tabstop=2
  60. set whichwrap+=<,>,[,],h,l
  61. set undofile
  62. set undodir=~/.vim/undo
  63. " Colorscheme
  64. " colorscheme minimalist
  65. colorscheme nord
  66. highlight Comment cterm=italic
  67. highlight Pmenu ctermbg=233
  68. set background=dark
  69. " Lightline
  70. set laststatus=2
  71. set noshowmode
  72. " Source lightline theme
  73. if empty(glob('~/.vim/source/minimalist.vim'))
  74. silent !curl -fLO --create-dirs --output-dir ~/.vim/source https://public.viktorgrahn.com/minimalist.vim
  75. endif
  76. source ~/.vim/source/minimalist.vim
  77. let g:lightline = {
  78. \ 'colorscheme': 'nord',
  79. \ 'tabline_subseparator': { 'left': '', 'right': '' },
  80. \ 'active': {
  81. \ 'left': [
  82. \ [ 'mode', 'paste' ],
  83. \ [ 'filestate' ],
  84. \ [ 'gitbranch', 'tagbar' ],
  85. \ ],
  86. \ 'right': [
  87. \ [ 'linter_checking', 'linter_errors', 'linter_warnings', 'linter_infos', 'linter_ok' ],
  88. \ [ 'fileformat', 'fileencoding', 'filetype', 'percent', 'lineinfo', 'offset' ],
  89. \ ]
  90. \ },
  91. \ 'tabline': {
  92. \ 'left': [ [ 'tabs' ] ],
  93. \ 'right': [ ],
  94. \ },
  95. \ 'component': {
  96. \ 'tagbar': '%{tagbar#currenttag("%s", "", "f", "nearest-stl")}',
  97. \ },
  98. \ 'component_function': {
  99. \ 'filestate': 'LightlineFileState',
  100. \ 'offset': 'LightlineFileOffset',
  101. \ },
  102. \ 'component_expand': {
  103. \ 'gitbranch': 'FugitiveHead',
  104. \ 'linter_checking': 'lightline#ale#checking',
  105. \ 'linter_infos': 'lightline#ale#infos',
  106. \ 'linter_warnings': 'lightline#ale#warnings',
  107. \ 'linter_errors': 'lightline#ale#errors',
  108. \ 'linter_ok': 'lightline#ale#ok',
  109. \ },
  110. \ 'component_type': {
  111. \ 'linter_warnings': 'warning',
  112. \ 'linter_errors': 'error',
  113. \ 'linter_ok': 'ok',
  114. \ 'linter_infos': 'info',
  115. \ }
  116. \ }
  117. " Lightline helper (concatenate readonly state, filename and modified state)
  118. function! LightlineFileState()
  119. if @% == "" | return "[No name]" | endif
  120. let s = expand('%:t')
  121. if &modified | let s = s . "+" | endif
  122. if &readonly | let s = "[RO] " . s | endif
  123. return s
  124. endfunction
  125. " Lightline helper (get cursor line and character position in file)
  126. function! LightlineFileOffset()
  127. return line2byte(line('.')) + col('.') - 1
  128. endfunction
  129. " NERDtree
  130. let NERDTreeQuitOnOpen=1
  131. let NERDTreeShowHidden=1
  132. " NERDTree helper (toggle in current buffer)
  133. function! NERDTreeToggleCustom()
  134. if (exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) != -1)
  135. exe ":NERDTreeClose"
  136. elseif bufname('%') != ""
  137. exe ":NERDTreeFind"
  138. else
  139. exe ":NERDTreeCWD"
  140. endif
  141. endfunction
  142. " NERDTREE Toggle NERDTree on <space>-o
  143. map <Space>o :call NERDTreeToggleCustom()<CR>
  144. " NERDTree fix for menu bug
  145. let g:NERDTreeMinimalMenu=1
  146. " ALE Configuration
  147. let g:ale_completion_enabled = 0
  148. let g:ale_sign_column_always = 1
  149. let g:ale_set_signs = 1
  150. let g:ale_set_highlights = 0
  151. let g:ale_disable_lsp = 1
  152. " QD for intelephense stubs
  153. let s:intelephense_config = {
  154. \ 'stubs': [ 'apache', 'bcmath', 'bz2', 'calendar', 'com_dotnet', 'Core', 'ctype', 'curl', 'date', 'dba', 'dom', 'enchant', 'exif', 'FFI', 'fileinfo', 'filter', 'fpm', 'ftp', 'gd', 'gettext', 'gmp', 'hash', 'iconv', 'imap', 'intl', 'json', 'ldap', 'libxml', 'mbstring', 'meta', 'mongodb', 'mysqli', 'oci8', 'odbc', 'openssl', 'pcntl', 'pcre', 'PDO', 'pdo_ibm', 'pdo_mysql', 'pdo_pgsql', 'pdo_sqlite', 'pgsql', 'Phar', 'posix', 'pspell', 'readline', 'Reflection', 'session', 'shmop', 'SimpleXML', 'snmp', 'soap', 'sockets', 'sodium', 'SPL', 'sqlite3', 'standard', 'superglobals', 'sysvmsg', 'sysvsem', 'sysvshm', 'tidy', 'tokenizer', 'xml', 'xmlreader', 'xmlrpc', 'xmlwriter', 'xsl', 'ZendOPcache', 'zip', 'zlib' ],
  155. \ 'files': {
  156. \ 'maxSize': 2000000
  157. \ },
  158. \}
  159. if exists("*ale#linter#Define")
  160. " Custom intelephense
  161. call ale#linter#Define('php', {
  162. \ 'name': 'intelephense-debug',
  163. \ 'lsp': 'stdio',
  164. \ 'initialization_options': function('ale_linters#php#intelephense#GetInitializationOptions'),
  165. \ 'executable': {b -> ale#path#FindExecutable(b, 'php_intelephense', [])},
  166. \ 'command': '%e --stdio',
  167. \ 'project_root': function('ale_linters#php#intelephense#GetProjectRoot'),
  168. \ 'lsp_config': s:intelephense_config,
  169. \})
  170. endif
  171. " ALE linters
  172. let g:ale_use_global_executables = 1
  173. let g:ale_linters_explicit = 1
  174. let g:ale_linters = {}
  175. let g:ale_linters.javascript = [ 'eslint' ]
  176. let g:ale_linters.php = [ 'intelephense-debug', 'phpcs', 'phpmd' ]
  177. let g:ale_linters.go = [ 'gopls', 'gofmt', 'gobuild' ]
  178. let g:ale_linters.json = [ 'jsonlint', 'jq' ]
  179. let g:ale_history_log_output = 1
  180. let g:ale_virtualtext_cursor = 'current'
  181. let g:ale_phpcs_standard = "PSR2"
  182. let g:ale_php_phpmd_ruleset = 'cleancode'
  183. let g:ale_php_intelephense_executable = 'debugIntelephense.sh'
  184. " ALE fixers
  185. let g:ale_fixers = { '*': [ 'remove_trailing_lines', 'trim_whitespace' ] }
  186. let g:ale_fixers.javascript = [ 'prettier', 'eslint' ]
  187. let g:ale_fixers.json = [ 'prettier' ]
  188. let g:ale_fixers.go = [ 'gofmt', 'goimports' ]
  189. " ALE message should include responsible linter
  190. let g:ale_echo_msg_format = '[%linter%] %s'
  191. " Ale keymaps
  192. nnoremap <C-a>l :ALELint<CR>
  193. nnoremap <C-a>f :ALEFix<CR>
  194. nnoremap <C-a>i :ALEInfo<CR>
  195. nnoremap <C-a>n :ALENext<CR>
  196. nnoremap <C-a>p :ALEPrevious<CR>
  197. " ALE styling
  198. highlight ALEErrorSign ctermbg=237 ctermfg=167
  199. highlight ALEWarningSign ctermbg=237 ctermfg=215
  200. highlight ALEInfoign ctermbg=237 ctermfg=117
  201. " ALE Configuration end
  202. " Tagbar
  203. let g:tagbar_autoclose = 1
  204. let g:tagbar_autofocus = 1
  205. let g:tagbar_map_showproto = ''
  206. nmap <Space>t :TagbarToggle<CR>
  207. " Toggle transparent background
  208. let g:is_transparent = 0
  209. function! Toggle_transparent()
  210. echo g:is_transparent
  211. if g:is_transparent == 0
  212. hi Normal guibg=NONE ctermbg=NONE
  213. hi NonText guibg=NONE ctermbg=NONE
  214. let g:is_transparent = 1
  215. else
  216. set background=dark
  217. let g:is_transparent = 0
  218. endif
  219. endfunction
  220. nnoremap <Space>T :call Toggle_transparent()<CR>
  221. " Location list toggle
  222. function! Toggle_location_list()
  223. if get(b:, 'location_list', 0) == 0
  224. silent! lopen
  225. if get(getloclist(0, { 'winid': 0 }), 'winid')
  226. let b:location_list = 1
  227. endif
  228. else
  229. lclose
  230. let b:location_list = 0
  231. endif
  232. endfunction
  233. nnoremap <Space>l :call Toggle_location_list()<CR>
  234. " Quickfix list toggle
  235. function! Toggle_quick_list()
  236. if get(b:, 'quick_list', 0) == 0
  237. silent! copen
  238. if get(getqflist(0, { 'winid': 0 }), 'winid')
  239. let b:quick_list = 1
  240. endif
  241. else
  242. cclose
  243. let b:quick_list = 0
  244. endif
  245. endfunction
  246. nnoremap <Space>c :call Toggle_quick_list()<CR>
  247. " Git blame
  248. autocmd BufEnter * if !exists("b:git_blame") | let b:git_blame = 0 | endif
  249. function! Toggle_git_blame()
  250. if b:git_blame == 0
  251. :silent! Git blame
  252. let b:git_blame = 1
  253. else
  254. let winIndex = 1
  255. let winCnt = winnr('$')
  256. while winIndex <= winCnt
  257. if expand('%:e') == "fugitiveblame"
  258. :close
  259. else
  260. :wincmd w
  261. endif
  262. let winIndex += 1
  263. endwhile
  264. let b:git_blame = 0
  265. endif
  266. endfunction
  267. nnoremap <Space>b :call Toggle_git_blame()<CR>
  268. " Git gutter
  269. nmap <C-g>n :GitGutterNextHunk<CR>
  270. nmap <C-g>p :GitGutterPrevHunk<CR>
  271. " Fuzzy search
  272. nmap <Space>f :Files<CR>
  273. nmap <Space>s :Rg<CR>
  274. nmap <Space>w :Windows<CR>
  275. " Setting title to enable better tmux titling
  276. if exists('$TMUX')
  277. autocmd BufReadPost,FileReadPost,BufNewFile,BufEnter * call UpdateTmuxWindow()
  278. autocmd VimLeave * call system("tmux setw automatic-rename")
  279. endif
  280. function UpdateTmuxWindow()
  281. let excludedFiletypes = [ 'help', 'qf', 'nerdtree' ]
  282. if index(excludedFiletypes, &filetype) < 0
  283. let title = @% == "" ? "vim" : "vim (" . expand("%:t") . ")"
  284. call system("tmux rename-window '" . title . "'")
  285. endif
  286. endfunction
  287. " Format XML pretty
  288. function! PrettyXML()
  289. set filetype=xml
  290. silent %!xmllint --format --encode UTF-8 --recover - 2>/dev/null
  291. endfunction
  292. " Format json pretty
  293. function! PrettyJSON()
  294. set filetype=json
  295. silent %!python3 -m json.tool
  296. endfunction
  297. nmap <Space>x :call PrettyXML()<CR>
  298. nmap <Space>j :call PrettyJSON()<CR>
  299. " Diff since save
  300. nmap <Space>d :w !diff -y --suppress-common-lines --color % -<CR>
  301. " Navigation keymaps
  302. inoremap <C-h> <Left>
  303. inoremap <C-l> <Right>
  304. inoremap <C-j> <Down>
  305. inoremap <C-k> <Up>
  306. " Disable bad default keybindings
  307. inoremap <C-w> <Nop>
  308. " LSP configuration
  309. let g:lsc_enable_diagnostics = v:false
  310. let g:lsc_auto_map = v:true
  311. let g:lsc_autocomplete_length=1
  312. set omnifunc=lsc#complete#complete
  313. " LSP keymappings
  314. nnoremap <C-l>f :LSClientFindReferences<CR>
  315. nnoremap <C-l>g :tab LSClientGoToDefinitionSplit<CR>
  316. nnoremap <C-l>G :LSClientGoToDefinition<CR>
  317. nnoremap <C-l>h :LSClientShowHover<CR>
  318. nnoremap <C-l>s :LSClientSignatureHelp<CR>
  319. inoremap <C-l>s <C-o>:LSClientSignatureHelp<CR>
  320. " LSP servers
  321. let lsc_server_defaults = { 'log_level': -1, 'suppress_stderr': v:true }
  322. let g:lsc_server_commands = {
  323. \ 'javascript': extend({ 'command': 'typescript-language-server --stdio'}, lsc_server_defaults),
  324. \ 'javascript.jsx': extend({ 'command': 'typescript-language-server --stdio'}, lsc_server_defaults),
  325. \ 'go': extend({ 'command': 'gopls serve' }, lsc_server_defaults),
  326. \ 'php': extend({ 'command': 'intelephense --stdio', 'message_hooks': {'initialize': { 'initializationOptions': {'storagePath': '/tmp/intelephense'} } } }, lsc_server_defaults),
  327. \}
  328. " LSP close preview after selecting completion
  329. autocmd CompleteDone * silent! pclose
  330. " LSP close quickfix list after selection
  331. autocmd BufLeave * cclose
  332. " Auto expand
  333. inoremap (; (<CR>);<C-c>O
  334. inoremap (, (<CR>),<C-c>O
  335. inoremap (<CR> (<CR>)<C-c>O
  336. inoremap {; {<CR>};<C-c>O
  337. inoremap {, {<CR>},<C-c>O
  338. inoremap {<CR> {<CR>}<C-c>O
  339. inoremap [; [<CR>];<C-c>O
  340. inoremap [, [<CR>],<C-c>O
  341. inoremap [<CR> [<CR>]<C-c>O