0

Summary

I configured vim to call clang-format.py following the steps in the clang documentation for vim integration. But when I save a new buffer the plugin fails. I'm new to vimscript and trying to figure out a solution.

Details

I used homebrew to install clang-format on a Mac OS Catalina system. I used the following steps shown in clang documentation for vim integration to enable running clang-format on write to file (only difference in my configuration compared to the website is the path to clang-format.py):

function! Formatonsave()
  let l:formatdiff = 1
  pyf /usr/local/Cellar/clang-format/11.0.0/share/clang/clang-format.py
endfunction

This works fine if I save an existing buffer, but if I create a new buffer I get the following error:

Error detected while processing function Formatonsave:                                                                                                                            
line    2:                                                                                                                                                                        
Traceback (most recent call last):                                                                                                                                                
  File "<string>", line 1, in <module>                                                                                                                                            
  File "/usr/local/Cellar/clang-format/11.0.0/share/clang/clang-format.py", line 156, in <module>                                                                                 
    main()                                                                                                                                                                        
  File "/usr/local/Cellar/clang-format/11.0.0/share/clang/clang-format.py", line 80, in main                                                                                      
    with open(vim.current.buffer.name, 'r') as f:                                                                                                                                 
"test.cpp" [New] 4L, 46C written  

For completeness my steps to reproduce are to run vim test.cpp (where test.cpp does not exist yet), then add the following content:

int main( ) { return 0 ; }

And use :w to save the file. This results in the error shown earlier.

Looking at the clang-format.py code I think the error is happening because the clang-format.py script it trying to read the file from disk before it is created

  elif vim.eval('exists("l:formatdiff")') == '1':
    with open(vim.current.buffer.name, 'r') as f:
      ondisk = f.read().splitlines();
    sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)

At this point I think I understand the issue. But I don't know much about vimscript so I'm hoping someone here might be able to suggest a solution. If there were a way to call a different function when saving a new buffer (as opposed to one when the file already exists) that would work. But I haven't found an option for that yet. And perhaps there is a better alternative. Also I'm surprised that other people haven't seen this issue. So it's possible there's something in my vim config that is unique and causing the problem. I'd be curious if others can reproduce this problem too or not.

3
  • It looks like the read only happens if l:formatdiff is 1; I wonder if you could set it to a different value when the buffer represents a new file?
    – D. Ben Knoble
    Nov 8, 2020 at 0:32
  • is there a way for vim to know that buffer is being saved to file that is not already on disk? Nov 8, 2020 at 2:55
  • at a guess? Something like filereadable(bufname('%'))
    – D. Ben Knoble
    Nov 8, 2020 at 3:29

2 Answers 2

1

I don't know why the ClangFormat documentation recommends that approach, but it just makes things difficult.

You just need to set formatprg in ~/.vim/after/ftplugin/cpp.vim as follows:

setlocal formatprg=clang-format\ --style=GNU

and your autocommand:

augroup Format
    autocmd!
    autocmd BufWritePre <buffer> let winsaved = winsaveview() | execute 'normal gggqG' | call winrestview(winsaved)
augroup END

enter image description here

0

One solution I found is to modify clang-format.py to catch the error if the file is not found on disk. The downside of that is that I need to keep my own copy clang-format.py, so if there's a fix in vimrc that is probably still preferable. But in case anyone has the same question in the future, here's the workaround I'm using in clang-format.py file:

diff --git a/clang/tools/clang-format/clang-format.py b/clang/tools/clang-format/clang-format.py
index 76fedb64814..caf9834cd2d 100644
--- a/clang/tools/clang-format/clang-format.py
+++ b/clang/tools/clang-format/clang-format.py
@@ -77,8 +77,11 @@ def main():
   if vim.eval('exists("l:lines")') == '1':
     lines = ['-lines', vim.eval('l:lines')]
   elif vim.eval('exists("l:formatdiff")') == '1':
-    with open(vim.current.buffer.name, 'r') as f:
-      ondisk = f.read().splitlines();
+    try:
+      with open(vim.current.buffer.name, 'r') as f:
+        ondisk = f.read().splitlines();
+    except IOError:
+      ondisk = ""
     sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
     lines = []
     for op in reversed(sequence.get_opcodes()):
1
  • 1
    I guess theoretically you could contribute this back to the main source
    – D. Ben Knoble
    Nov 8, 2020 at 3:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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