0

I am using neovim to work on a Swift project, so I have set up an autocmd to run swiftformat when I write Swift files as shown.

autocmd BufWritePost * if count(['swift'],&filetype) | silent execute "!swiftformat %" | redraw! 

The command works as expected, but neovim is not reloading the file. Even running :checktime to cause a reload does nothing. If I add an | edit at the end of the command, the file is reloaded, but the screen moves to be centered at my cursor, which I don’t want.

If I change the autocmd to

autocmd BufWritePost * if count(['swift'],&filetype) | silent execute "!swiftformat %" | redraw!
    \ | silent execute "!sleep 2 && touch %" | redraw!

then the file is reloaded after write, but my cursor locks up for two seconds on write, which is clearly undesirable.

If I change the autocmd to

autocmd BufWritePost * if count(['swift'],&filetype) | silent execute "!swiftformat %" | redraw!
    \ | silent execute "!sleep 1 && touch %" | redraw!

then the cursor locks up for just one second on write, but the file does not reload.

My only explanation for this behavior is that neovim is checking if the file was modified by checking timestamps, and since the timestamp of nvim’s write and swiftformat’s/touch’s write are so close together that it doesn’t realize the buffer was modified. I tried removing the sleep but touching the file with a timestamp in the future to trick nvim, but this was unsuccessful too.

How do I work around these issues? Is there some way I can express that the file really has changed, even if the timestamp has not?

I have included my entire init.vim in case that would be useful.

" Specify a directory for plugins
call plug#begin('~/.config/nvim/plugged')

Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'keith/swift.vim'

" Initialize plugin system
call plug#end()

" Swift indentation
autocmd FileType swift set tabstop=4
autocmd FileType swift set softtabstop=0 
autocmd FileType swift set expandtab
autocmd FileType swift set shiftwidth=4
autocmd FileType swift set smarttab

" Automatically run swiftformat on write
autocmd BufWritePost * if count(['swift'],&filetype) | silent execute "!swiftformat %" | redraw!
                                                                                                                                                                            
" coc config                                                                                                                                                                
let g:coc_global_extensions = [                                                                                                                                             
  \ 'coc-snippets',                                                                                                                                                         
  \ 'coc-pairs',                                                                                                                                                            
  \ 'coc-sourcekit',                                                                                                                                                        
  \ 'coc-json',                                                                                                                                                             
  \ ]                                                                                                                                                                       
"  \ 'coc-prettier',                                                                                                                                                        
                                                                                                                                                                            
" Make <CR> auto-select the first completion item and notify coc.nvim to                                                                                                    
" format on enter, <cr> could be remapped by other vim plugin                                                                                                               
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
1
0

You can use winsaveview() and winrestoreview() to restore the view across the :edit operation.

At this point, it's much easier if you define a function to perform the operation:

function! SwiftFormat()
    silent !swiftformat %
    let view = winsaveview()
    silent edit
    call winrestview(view)
    redraw!
endfunction

augroup swiftFormat
    autocmd!
    autocmd BufWritePost * if &filetype ==# 'swift' | call SwiftFormat() | endif
augroup END

I'm also using an augroup, to prevent the autocmd from being duplicated if you reload your vimrc. You were also missing an endif at the end of your definition. It's also possible to compare &filetype directly, no need to use count() around it.

4
  • 1
    Thanks for the great feedback! I am learning this stuff, so this is all very helpful. I was doing the count() thing because I was originally planning to run my script on more than 1 filetype. Is there something better than count() in that case? – deaton.dg May 1 at 23:12
  • Since we’re in an augroup now, is it better to have the if &filetype thing, or should I autocmd FileType with an autocmd BufWritePost inside? – deaton.dg May 1 at 23:17
  • The if &filetype is better. If you want to define an autocmd inside a filetype autocmd, then you need to make it a buffer-local command (since filetype is per buffer). You'd need autocmd FileType swift autocmd BufWritePost <buffer> call SwiftFormat(). But I think if &filetype is better, since you're not littering autocmd's for each new buffer you open... – filbranden May 1 at 23:28
  • I'll admit I read the Q&A pretty quickly but if you can reliably match your Swift files by a finite number of file extensions then an alternative should be autocmd BufWritePost *.swift call SwiftFormat() (assuming that's the only extension...comma separate others if needed). – B Layer May 2 at 3:02

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.