I am trying to format PHP files using the following function:

function! PHPCSFixer()                                                                                   
    let l:fixer_path = '$HOME/.devtools/php/php-cs-fixer-v2.phar'               
    let l:config_path = '$HOME/.devtools/php/php-cs-fixer.conf'                 
    let l:cmd = l:fixer_path . ' fix --quiet --config="' . l:config_path . '" -- "' . expand('%:p') . '"'
    :call system(l:cmd)                                                         
command! PHPCSFixer call PHPCSFixer()                                           
autocmd BufWritePost *.php silent :PHPCSFixer                                   

It just run the following script on the current file (https://github.com/FriendsOfPHP/PHP-CS-Fixer).

The problem is that every once in a while when I save (:w) a PHP file a warning pops up:

WARNING: The file has been changed since reading it!!!
Do you really want to write to it (y/n)?

I guess there is a timing problem somewhere but I don't know how/what to do to fix it...

Can someone point me to the right direction on this issue?

  • Welcome to Vi and Vim! You may want to investigate whether or not that script can run as a filter of stdin to stdout—it would avoid this problem altogethee – D. Ben Knoble Jul 29 at 16:23
  • Hmm I don't understand what you mean by that, can you explain that a little more? Thanks! – Jesus_21 Jul 30 at 18:49
  • cat, sort, awk, sed, grep, these are all commands that take input, filter it (or not, in the case of cat), and produce output. This makes it very easy to filter a buffer through the command without needing to :edit! afterwards. Can your formatter take the code to format as standard input and produce the result on standard output, or does it only work by modifying files in-place? – D. Ben Knoble Jul 30 at 18:52
  • OK, I get your point now. The fixer does take input from stdin but it does not output the result to stdout :| There is issues opened on the git repo of the fixer but they don't seem to plan that... The stdin input is pretty useless as far as I can tell. I guess I can write to a tmp file, fix it, cat to the buffer :/ – Jesus_21 Jul 31 at 8:33

I came up with the following solution:

" make a tmp file & write buffer content to it
let l:tmp = system('mktemp')
execute 'write! ' . l:tmp

" fix the tmp file
let l:cmd = l:fixer_path . ' fix --quiet --config="' . l:config_path . '" -- "' . l:tmp . '"'
call system(l:cmd)

" cat tmp file to buffer & keep cursor pos
let l:save_cursor = getpos('.')
execute '%!cat ' . l:tmp
call setpos('.', l:save_cursor)

execute '!rm ' . l:tmp

Not very elegant I guess but working

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.