├── doc └── phpfmt.txt ├── third_party └── phpcbf.phar ├── LICENSE ├── plugin └── phpfmt.vim ├── autoload └── phpfmt │ ├── log.vim │ └── fmt.vim └── README.md /doc/phpfmt.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third_party/phpcbf.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beanworks/vim-phpfmt/HEAD/third_party/phpcbf.phar -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Beanworks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /plugin/phpfmt.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_phpfmt_plugin') || &compatible 2 | finish 3 | endif 4 | let g:loaded_phpfmt_plugin = 1 5 | let g:phpfmt_root_dir = fnamemodify(globpath(&rtp, "plugin/phpfmt.vim"), ":h:h") 6 | 7 | for s:feature in [ 8 | \ 'autocmd', 9 | \ 'reltime' 10 | \ ] 11 | if !has(s:feature) 12 | call phpfmt#log#error('need Vim compiled with feature ' . s:feature) 13 | finish 14 | endif 15 | endfor 16 | 17 | if has('reltime') 18 | let g:_PHPFMT_START = reltime() 19 | lockvar! g:_PHPFMT_START 20 | endif 21 | 22 | if !exists('g:phpfmt_command') 23 | let g:phpfmt_command = g:phpfmt_root_dir . '/third_party/phpcbf.phar' 24 | if !executable(g:phpfmt_command) 25 | call phpfmt#log#error('oops, phpcbf.phar is not executable. Check ' . g:phpfmt_command) 26 | endif 27 | endif 28 | 29 | if !exists('g:phpfmt_standard') 30 | let g:phpfmt_options = '--standard=PSR2 --encoding=utf-8' 31 | else 32 | let g:phpfmt_options = '--standard=' . g:phpfmt_standard . ' --encoding=utf-8' 33 | endif 34 | 35 | if !exists("g:phpfmt_experimental") 36 | let g:phpfmt_experimental = 0 37 | endif 38 | 39 | command! -bar PhpFmt call phpfmt#fmt#format() 40 | 41 | augroup vim-phpfmt 42 | autocmd! 43 | autocmd BufWritePre *.php call phpfmt#fmt#autoformat() 44 | augroup END 45 | -------------------------------------------------------------------------------- /autoload/phpfmt/log.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_phpfmt_log_autoload') || !exists('g:loaded_phpfmt_plugin') 2 | finish 3 | endif 4 | let g:loaded_phpfmt_log_autoload = 1 5 | 6 | function! phpfmt#log#info(msg) abort "{{{ 7 | echomsg 'phpfmt: info: ' . a:msg 8 | endfunction "}}} 9 | 10 | function! phpfmt#log#warn(msg) abort "{{{ 11 | echohl WarningMsg 12 | echomsg 'phpfmt: warning: ' . a:msg 13 | echohl None 14 | endfunction "}}} 15 | 16 | function! phpfmt#log#error(msg) abort "{{{ 17 | execute "normal \" 18 | echohl ErrorMsg 19 | echomsg 'phpfmt: error: ' . a:msg 20 | echohl None 21 | endfunction "}}} 22 | 23 | function! phpfmt#log#debug(level, msg, ...) abort "{{{ 24 | if !s:_isDebugEnabled(a:level) 25 | return 26 | endif 27 | 28 | let leader = s:_log_timestamp() 29 | call s:_logRedirect(1) 30 | 31 | if a:0 > 0 32 | " filter out dictionary functions 33 | echomsg leader . a:msg . ' ' . 34 | \ strtrans(string(type(a:1) == type({}) || type(a:1) == type([]) ? 35 | \ filter(copy(a:1), 'type(v:val) != type(function("tr"))') : a:1)) 36 | else 37 | echomsg leader . a:msg 38 | endif 39 | 40 | call s:_logRedirect(0) 41 | endfunction "}}} 42 | 43 | " ---------- Private functions ---------- 44 | 45 | function! s:_isDebugEnabled_smart(level) abort "{{{ 46 | return and(g:phpfmt_debug, a:level) 47 | endfunction "}}} 48 | 49 | function! s:_isDebugEnabled_dumb(level) abort " {{{ 50 | " poor man's bit test for bit N, assuming a:level == 2**N 51 | return (g:phpfmt_debug / a:level) % 2 52 | endfunction " }}} 53 | 54 | let s:_isDebugEnabled = function(exists('*and') ? 's:_isDebugEnabled_smart' : 's:_isDebugEnabled_dumb') 55 | lockvar s:_isDebugEnabled 56 | 57 | function! s:_logRedirect(on) abort "{{{ 58 | if exists('g:phpfmt_debug_file') 59 | if a:on 60 | try 61 | execute 'redir >> ' . fnameescape(expand(g:phpfmt_debug_file, 1)) 62 | catch /\m^Vim\%((\a\+)\)\=:/ 63 | silent! redir END 64 | unlet g:phpfmt_debug_file 65 | endtry 66 | else 67 | silent! redir END 68 | endif 69 | endif 70 | endfunction "}}} 71 | 72 | function! s:_log_timestamp_smart() abort "{{{ 73 | return printf('phpfmt: %f: ', reltimefloat(reltime(g:_PHPFMT_START))) 74 | endfunction "}}} 75 | 76 | function! s:_log_timestamp_dumb() abort "{{{ 77 | return 'phpfmt: ' . split(reltimestr(reltime(g:_PHPFMT_START)))[0] . ': ' 78 | endfunction "}}} 79 | 80 | let s:_log_timestamp = function(has('float') && exists('*reltimefloat') ? 's:_log_timestamp_smart' : 's:_log_timestamp_dumb') 81 | lockvar s:_log_timestamp 82 | -------------------------------------------------------------------------------- /autoload/phpfmt/fmt.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_phpfmt_fmt_autoload') || !exists('g:loaded_phpfmt_plugin') 2 | finish 3 | endif 4 | let g:loaded_phpfmt_fmt_autoload = 1 5 | 6 | function! phpfmt#fmt#autoformat() abort "{{{ 7 | if get(g:, 'phpfmt_autosave', 1) 8 | call phpfmt#fmt#format() 9 | endif 10 | endfunction "}}} 11 | 12 | function! phpfmt#fmt#format() abort "{{{ 13 | if g:phpfmt_experimental == 1 14 | " Using winsaveview to save/restore cursor state has the problem of 15 | " closing folds on save. One fix is to use mkview instead. Unfortunately, 16 | " this sometimes causes other bad side effects, and still closes all folds 17 | " if foldlevel>0. 18 | let l:curw = {} 19 | try 20 | mkview! 21 | catch 22 | let l:curw=winsaveview() 23 | endtry 24 | else 25 | " Save cursor position and many other things. 26 | let l:curw=winsaveview() 27 | endif 28 | 29 | " Write current unsaved buffer to a temp file 30 | if exists('g:phpfmt_tmp_dir') 31 | let l:tmpdir = g:phpfmt_tmp_dir . expand('%:h') 32 | if !isdirectory(l:tmpdir) 33 | exe 'silent! !mkdir -p ' . shellescape(l:tmpdir, 1) 34 | endif 35 | let l:tmpname = g:phpfmt_tmp_dir . expand('%') 36 | else 37 | let l:tmpname = tempname() 38 | endif 39 | call writefile(getline(1, '$'), l:tmpname) 40 | 41 | if g:phpfmt_experimental == 1 42 | " save our undo file to be restored after we are done. This is needed to 43 | " prevent an additional undo jump due to BufWritePre auto command and also 44 | " restore 'redo' history because it's getting being destroyed every 45 | " BufWritePre 46 | let tmpundofile=tempname() 47 | exe 'wundo! ' . tmpundofile 48 | endif 49 | 50 | " populate the final command with user based fmt options 51 | let command = g:phpfmt_command . ' ' . g:phpfmt_options 52 | " execute our system command... 53 | call system(command . ' ' . l:tmpname) 54 | 55 | " remove undo point caused via BufWritePre 56 | try | silent undojoin | catch | endtry 57 | " reload buffer 58 | let old_fileformat = &fileformat 59 | call rename(l:tmpname, expand('%')) 60 | silent edit! 61 | let &fileformat = old_fileformat 62 | let &syntax = &syntax 63 | 64 | if g:phpfmt_experimental == 1 65 | " restore our undo history 66 | silent! exe 'rundo ' . tmpundofile 67 | call delete(tmpundofile) 68 | endif 69 | 70 | if g:phpfmt_experimental == 1 71 | " Restore our cursor/windows positions, folds, etc. 72 | if empty(l:curw) 73 | silent! loadview 74 | else 75 | call winrestview(l:curw) 76 | endif 77 | else 78 | " Restore our cursor/windows positions. 79 | call winrestview(l:curw) 80 | endif 81 | endfunction "}}} 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-phpfmt 2 | 3 | PHP auto format plugin for vim. It works seamlessly with phpcbf, and automatically 4 | formats currently editing PHP file on save, or by manually running command `:PhpFmt`. 5 | 6 | ## Install 7 | 8 | Vim-phpfmt follows the standard runtime path structure, so we highly recommend to 9 | use a common and well known plugin manager to install vim-phpfmt. For Pathogen just 10 | clone the repo. For other plugin managers add the appropriate lines and execute the 11 | plugin's install command. 12 | 13 | * [Pathogen](https://github.com/tpope/vim-pathogen): `git clone https://github.com/beanworks/vim-phpfmt.git ~/.vim/bundle/vim-phpfmt` 14 | * [vim-plug](https://github.com/junegunn/vim-plug): `Plug 'beanworks/vim-phpfmt'` 15 | * [NeoBundle](https://github.com/Shougo/neobundle.vim): `NeoBundle 'beanworks/vim-phpfmt'` 16 | * [Vundle](https://github.com/gmarik/vundle): `Plugin 'beanworks/vim-phpfmt'` 17 | 18 | ## Settings 19 | 20 | By default `third_party/phpcbf.phar` is used to format PHP code with `PSR2` as the 21 | default standard. To change to a different standard type or file, add the following 22 | setting to your vimrc file: 23 | 24 | ```vim 25 | " A standard type: PEAR, PHPCS, PSR1, PSR2, Squiz and Zend 26 | let g:phpfmt_standard = 'PSR2' 27 | 28 | " Or your own defined source of standard (absolute or relative path): 29 | let g:phpfmt_standard = '/path/to/custom/standard.xml' 30 | ``` 31 | 32 | Vim-phpfmt will first writes buffer to a temp file in the temp folder configured, then runs 33 | phpcbf over the temp file, and then copies formatted content back to the editing view, and 34 | restores cursor position. 35 | 36 | Auto format on save is enabled by default, to disable it: 37 | 38 | ```vim 39 | let g:phpfmt_autosave = 0 40 | ``` 41 | 42 | For more precise control, you can specify paths to your own phpcbf executable, or another 43 | PHP formatter of your choice. You can also set up a different temp file storing folder for 44 | intermediate formatting buffer: 45 | 46 | ```vim 47 | let g:phpfmt_command = '/path/to/phpcbf' 48 | let g:phpfmt_tmp_dir = '/path/to/tmp/folder' 49 | ``` 50 | 51 | ## Usage 52 | 53 | Once the settings are in place, invoke command `:PhpFmt` to call the formatter. If auto 54 | format is enabled by setting `:w` or `:x` will automatically triggers the formatter. 55 | 56 | ## Working with Docker 57 | 58 | If you are using docker for dev, and having phpcbf executable installed inside the container, 59 | along with your own standard source. You can still use vim-phpfmt. 60 | 61 | Assume you have mounted source code folders as volumes to the container, you can then change 62 | the settings to: 63 | 64 | ```vim 65 | " NOTE: all the paths below should be pointing to executable, standard file, 66 | " and tmp folder that are actually inside the container 67 | let g:phpfmt_command = 'docker exec container_name /path/to/phpcbf' 68 | let g:phpfmt_options = '--standard=/path/to/custom/standard.xml --encoding=utf-8' 69 | let g:phpfmt_tmp_dir = '/path/to/tmp/folder' 70 | ``` 71 | --------------------------------------------------------------------------------