Writing PHP and JS with Vim in 2017

Here’s the bits from my vimrc I’d recommend to anyone using vim or neovim for PHP development. These settings provide

  • Good indentation and syntax highlighting for PHP, Vue, Twig, Blade, Javascript, and Scss files. It even shows 4-space indentation in a reasonable way.
  • Reasonable, asynchronous code completion for PHP and JavaScript thanks to language specific completion engines.
  • Asynchronous code linting while you’re typing.
  • Support for Emmet and Editorconfig.
  • I didn’t include any ‘fuzzy open file` plugin like ctrlp.vim, denite, or fzf.vim. This is mostly because I don’t use any of these, but I’d recommend that you pick one and give it a go.

Plugins

Plugin Manager: vim-plug

There’s tons of these now — pathogen, vundle, dein, VAM, apt-vim — but I like junegunn/vim-plug the most. It seems simpler and faster than the others.

Base Plugins

  • 2072/PHP-Indenting-for-VIm —a version of this plugin is already part of vim, but there’s minor bug fixes available if you get the newer version from GitHub.
  • Yggdroot/indentLine — if you follow PHP-FIG PSR-2, then you indent at least your PHP code with four spaces. This plugin lets you highlight the indent levels even though it’s all spaces.
  • chrisbra/Colorizer — this lets you highlight html, hex, rgb(), and even hsl() colors in the their respective colors. It’s a great help for working with CSS.
  • chriskempson/base16-vim — this is a package of plenty, high quality, consistent, light and dark color themes.
  • mhinz/vim-signify — uses a column on the left to highlight what you’ve changed since you last committed. Great for seeing your changes and making sure there’s nothing unwanted.
  • sheerun/vim-polyglot — great collection of filetype plugins that cover all kinds of modern filetypes, including .vue files, dockerfiles, blade, json, markdown, sass, twig, even haml and coffee-script.
  • w0rp/ale —linting (mostly syntax checking) as you’re editing. It’s fast, and can use php -l, eslint, lint vue files, and all kinds of magic. If you used vim-syntastic/syntastic previously, ALE is worth checking out.

Code Analysis and Completion

  • lvht/phpcd.vim — uses real PHP reflection to provide PHP completions.
  • ternjs/tern_for_vim — similiarly, uses JS’s ternjs to provide JS completions.
  • Shougo/deoplete.nvim — there’s probably even more completion plugins than package managers out there: supertab, YouCompleteMe, VimCompletesMe, completor, nvim-completion-manager, mucomplete — but again, I like deoplete the most. It’s fast, configurable, and plays well with tern_for_vim and phpcd.

Additional Features

  • mileszs/ack.vim — just a better way to search through all files from within vim, which can use some of the better grep alternatives (ack, ag, even ripgrep.) I use it with ripgrep these days.
  • mattn/emmet-vim — anyone who writes any HTML should learn emmet. It’s just a shorthand for writing HTML and CSS, and it’s supported by nearly every editor and even JSFiddle, JSBin, and CodePen.
  • editorconfig/editorconfig-vim — editorconfig is the best solution if you need different formatting settings for different projects. It also works with lots of other editors, so it’s a handy thing to use at work, where you can commit .editorconfig files for projects that don’t follow standards.
  • scrooloose/nerdtree — NERDTree is still the simplest way to browse files, especially if you’re coming from Sublime Text, Atom, or VSCode, or PHPStorm. If you want something more vim-like, Vinegar and Dirvish are both great choices as well as trying out netrw’s :Lex.

All plugins as a vimrc snippet:

call plug#begin()
Plug '2072/PHP-Indenting-for-VIm'    " PHP indent script
Plug 'Yggdroot/indentLine' " highlighting 4sp indenting
Plug 'chrisbra/Colorizer' " colorize colors
Plug 'chriskempson/base16-vim' " high quality colorschemes
Plug 'mhinz/vim-signify' " show VCS changes
Plug 'sheerun/vim-polyglot' " newer language support
Plug 'w0rp/ale' " realtime linting
" Code Analysis and Completion
Plug 'lvht/phpcd.vim', { 'for': 'php', 'do': 'composer install' }
Plug 'ternjs/tern_for_vim', { 'do': 'npm install' }
Plug 'Shougo/deoplete.nvim' " async completion
Plug 'roxma/nvim-yarp' " deoplete dependency
Plug 'roxma/vim-hug-neovim-rpc' " deoplete dependency
" Other Features
Plug 'mileszs/ack.vim' " ack/rg support
Plug 'mattn/emmet-vim' " emmet support
Plug 'editorconfig/editorconfig-vim' " editorconfig support
Plug 'scrooloose/nerdtree' " sidebar for browsing files
call plug#end()

Vim Settings

Next, here’s a bunch of setting’s I’d recommend.

set number ignorecase smartcase undofile spell list hlsearch incsearch lazyredraw
set fillchars=vert:\ ,fold:\ listchars=tab:⎸\ ,nbsp:⎕
set linebreak showbreak=↪\ breakindent breakindentopt=shift:-2
set formatoptions+=nj
let g:PHP_outdentphpescape = 0

Quickly going through these:

  • number turns on line numbering.
  • ignorecase smartcase makes searches case insensitive unless they contain capitals.
  • undofile preserves your undo history per file, through closing and opening a file again.
  • spell turns on spell checking.
  • list listchars=tab:⎸\ ,nbsp:⎕ makes tabs and non-breaking spaces visible.
  • hlsearch incsearch turns on highlighting search results and searching as you type.
  • lazyredraw is just for performance.
  • fillchars here is just hiding characters that are usually used to show vertical splits and folds, as since they’re already highlighted differently, the characters feel overkill.
  • set linebreak showbreak=↪\ breakindent breakindentopt=shift:-2 all of this just tweaks how lines are shown when they wrap.
  • set formatoptions+=nj turns on two formatoptions: ’n’ means it tries to automatically recognize and continue numbered lists, and ‘j’ tries to clean up leading ‘comment characters’ (like *) when you join lines within a comment.
  • let g:PHP_outdentphpescape = 0 means that PHP tags will match the indent of the HTML around them in files that a mix of PHP and HTML. I don’t think I’ve seen anyone write PHP within HTML that doesn’t want this these days.

Bonus: True Color Settings

set termguicolors
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
" Change cursor shape based on mode
let &t_SI = "\<Esc>[6 q"
let &t_SR = "\<Esc>[4 q"
let &t_EI = "\<Esc>[2 q"

These settings enable true color (if you terminal supports it) and changing the cursor shape based on mode (if your terminal supports that.)


Plugin Settings

Deoplete

let g:deoplete#enable_at_startup = 1
let g:deoplete#enable_yarp = 1
inoremap <expr><tab> pumvisible() ? "\<c-n>" : "\<tab>"
inoremap <expr><s-tab> pumvisible() ? "\<c-p>" : "\<s-tab>"
autocmd InsertLeave,CompleteDone * if pumvisible() == 0 | pclose | endif

First line enables deoplete on startup. Second line is necessary for vim only (not neovim.) Third and fourth lines let you use tab to move through deoplete’s completions. Last line closes the preview window automatically after selecting a completion.

ALE

let g:ale_sign_column_always = 1
let g:ale_sign_error = '⚑'
let g:ale_sign_warning = '⚐'

I found it jarring when ALE’s column on the left edge would disappear and reappear while I typed, so I recommend keeping is always visible. The next two lines here are just taking advantage of some unicode icons.

indentLine

let g:indentLine_char = "│"

Just setting what character to use to show the indent lines.

Polyglot

let g:vim_markdown_conceal = 0

Out of the box, polyglot’s markdown plugin does some fancy stuff with conceal to hide characters that indicate bold, italic, and links, and I found it quirkier than I liked. This turns that off, but leaves the support and highlighting.


Keybindings

These are easily the most personal settings in your vimrc, but I wanted to share a couple suggestions.

let mapleader="\<Space>"
nnoremap <silent> <Leader><Space> :nohlsearch<CR>

I, like many others, think that space makes a much better leader key than ‘\’ does. This second binding lets you hit space twice to clear search highlighting.


Final Thoughts

Neovim has made some great jumps forward in under-the-hood functionality from what Vim 7 had, and Vim 8 has picked up on a lot of it. Both have more sane defaults, and thanks to the plugin ecosystem, are simpler than ever to get rolling with all kinds of IDE features while still remaining the lightning fast, modal editors we love.