I am going to mostly document my own journy of setting up Vim (Not Neovim!) for PHP and laravel. Feel free to follow along.
We're going to use Vim+VimPlug+CoC.nvim, so we need to have nodejs and npm installed. It goes without saying that you should have Vim8+ as well. The current version of Vim as of this writing is Vim-9.1
So let's start from a clean ~/.vimrc
Lets place this block, that automatically installs VimPlug, on top of our ~/.vimrc
.
function! VimplugInstaller()
let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim'
if empty(glob(data_dir . '/autoload/plug.vim'))
silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
endfunction
call VimplugInstaller()
Followed by several essential plugins:
call plug#begin()
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'https://github.com/preservim/tagbar.git'
Plug 'vim-php/phpctags', {'for':'php'}
Plug 'honza/vim-snippets'
Plug 'SirVer/ultisnips'
Plug 'tpope/vim-commentary'
Plug 'sheerun/vim-polyglot'
Plug 'jwalton512/vim-blade'
call plug#end()
The most important one, is coc.nvim. The rest are for various enhancements, that we'll go over soon, but before we do, let's define some extensions for coc.nvim and configure the other plugins.
"===[Coc.nvim]==="
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#_select_confirm() : "\<C-g>u\<CR>"
" use <tab> to trigger completion and navigate to the next complete item
function! CheckBackspace() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
inoremap <silent><expr> <Tab>
\ coc#pum#visible() ? coc#pum#next(1) :
\ CheckBackspace() ? "\<Tab>" :
\ coc#refresh()
inoremap <expr><s-tab> coc#pum#visible() ? coc#pum#prev(1) : "\<c-h>"
" Enhanced <CR> for pairs
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
" Disable < expansion for pairs
autocmd FileType * let b:coc_pairs_disabled = ["<"]
"===[ Coc-Explorer ]==="
" set up coc-explorer to open in the current directory
let g:coc_explorer_global_mirror = 0
let g:coc_explorer_disable_default_keybindings = 1
let g:coc_explorer_global_root = 'current'
nnoremap <space>e <Cmd>CocCommand explorer<CR>
"===[ Coc Global Extensions ]==="
let g:coc_global_extensions = [
\ 'coc-html',
\ 'coc-css',
\ 'coc-pairs',
\ 'coc-emmet',
\ 'coc-explorer',
\ 'coc-phpactor',
\ 'coc-blade'
\ ]
" GoTo code navigation
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
" Use `[g` and `]g` to navigate diagnostics
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)
"
" List code actions available for the current buffer
nmap <leader>ca <Plug>(coc-codeaction)
nnoremap <silent> K :call ShowDocumentation()<CR>
function! ShowDocumentation()
if CocAction('hasProvider', 'hover')
call CocActionAsync('doHover')
else
call feedkeys('K', 'in')
endif
endfunction
" Add `:Format` command to format current buffer
command! -nargs=0 Format :call CocActionAsync('format')
" Formatting selected code
vmap <leader>f <Plug>(coc-format-selected)
" coc-pairs
" disable characters for a specified filetypes
autocmd FileType markdown let b:coc_pairs_disabled = ['txt']
The above code, configures tab completion, auto pairs, coc-explorer file explorer and other keybinding to get the most out of coc.nvim.
In the coc global extension section, we define extensions to be installed automatically. I have decided to use phpactor, you may change it for coc-intelephense
.
Lets also configure the snippets:
We can manage our snippets with coc.nvim too, but I choose to use UltiSnips for that.
"===[ SNIPPETS ]==="
"Use Ctrl j key to trigger the snippets, default was TAB but that conflicts with
"The Completion trigger see :h keycodes to change this to sth else
"Use Ctrl j and k to move visually within the snippet that was just triggered
"Ctrl l lists the available snippets
let g:UltiSnipsExpandTrigger='<C-j>'
let g:UltiSnipsListSnippets='<C-l>'
let g:UltiSnipsJumpForwardTrigger='<C-j>'
let g:UltiSnipsJumpBackwardTrigger='<C-k>'
let g:copypath_copy_to_unnamed_register = 1
Save and quit Vim and open it again and wait for the plugins and extensions to install.
If you get prompted by an error msg, just press enter and wait for the plugins and the extensions to install.
It's better to install the laravel extension manually:
:CocInstall @yaegassy/coc-laravel
Now lets configure the coc extensions.
Issue the :CocConfig
command from Vim's command mode and paste the following, inside the file.
{
"suggest.noselect": true,
"explorer.icon.enableNerdfont": true,
"explorer.file.reveal.auto": true
"languageserver": {
"phpactor": {
"command": "phpactor",
"args": ["language-server"],
"trace.server": "verbose",
"filetypes": ["php"]
}
}
}
If you choose to use a local installation of phpactor, you can just remove coc-phpactor
with :CocUninstall coc-phpactor
and modify the ~/.vim/coc-settings.json
to include a path to the phpactor executable and remove the languageserver block entirely.
{
"phpactor.enable": true,
"phpactor.path": "/usr/bin/phpactor",
}
The keybindings:
The only keybindings that you should know, besides the usual Vim keybindings, are:
Key | Action |
---|---|
Tab | completion |
gd | definition |
gy | type definition |
gi | implementation |
gr | references |
[g | diagnostics prev |
]g | diagnostics next |
ca | code actions |
K | hover docs |
f (in visual mode) | format code |
Ctrl-j | Expand Snippet & Move to Next Placeholder |
Ctrl+k | Move to Prev Placeholder |
Ctrl-l | List Snippets |
Space-e | Open Explorer |
Now we should have an efficient and comfortable setup for working with PHP and laravel.
Lets setup several other things for convenience
Theme:
Add these plugins to the plugins list and install them with :PlugInstall
after sourcing the ~/.vimrc
.
Plug 'ryanoasis/vim-devicons'
Plug 'catppuccin/vim', { 'as': 'catppuccin' }
Setup Vim to use the popular catppuccin theme.
"===[ Theme ]==="
set background=dark
" Inspect $TERM instead of t_Co
if &term =~ '256color'
" Enable true (24-bit) colors instead of (8-bit) 256 colors.
if has('termguicolors')
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
let &t_TI = ""
let &t_TE = ""
set termguicolors
set mouse=a
colorscheme catppuccin_mocha
endif
else
colorscheme catppuccin_mocha
let &t_TI = ""
let &t_TE = ""
endif
if has('gui_running')
set mouse=a
set guicursor+=a:blinkon0
set guifont=FiraCodeNerdFont\ 12
colorscheme catppuccin_mocha
endif
"===[ Curosr Shape ]==="
let &t_SI = "\<Esc>[6 q"
let &t_SR = "\<Esc>[4 q"
let &t_EI = "\<Esc>[2 q"
The above block, will make vim use termgui colors (in a termgui capable terminal) and use different cursor shapes for different modes.
Make sure your $TERM
variable reports xterm-256color
.
In the screenshot below, you can see phpactor, coc-explorer and tagbar at work.
I've left an error in the syntax to show you what the inline diagnostics look like.
It would do you well to familiarize yourself with the coc.nvim documentation and commands.
For example, running :CocDiagnostics
will open a drawer with all the errors found by coc.nvim.
Pressing enter on each item will jump you to the line containing the error.
I could not find a decent phpdoc plugin for Vim, but besides that, this setup is very effective.
You can find my full config on github, Woland's Vim and my personal ~/.vim
here.
If you have any notes or questions, please leave a comment.
Where to go from here
Start using the setup and tweak it to your needs, little by little. This is not a drop and go config, it's just a kickstarter to put it plainly.
Some general notes:
- Familiarize yourself with Vim's buffers.
- NEVER
:q
Vim, unless you're done for the day - Learn about
:vimgrep
and:lvimgrep
- Integrate fzf, ack, ag, rg into your workflow, (you need to quickly search large projects)
Possible Q&A
Can I use this with Nvim?
Yes, you just have to paste all the code into ~/.config/nvim/init.vim
Why not use Nvim with lspconfig and cmp etc ... ?
Because it takes way longer to configure and the results aren't better than what coc provides with so much ease.