clang-format emacs integration: window-start dislocation when formatting-before-save

As I wrote earlier, I’ve put this in my ~/.emacs to format my C++ buffers before they’re saved:

(add-hook 'c+±mode-hook
(add-hook 'before-save-hook 'clang-format-buffer)))

This worked fine when saving individual files with “C-x C-s”. However, I encountered a problem when using “C-x s” (save-some-buffers) where the window-start would be moved to the very first line, and the point would be moved to the left margin on the middle line in the window. In clang-format.el, I added some debug messages to show what’s happening with the calls to goto-char() and set-window-start(). What I found is that there’s nothing wrong with those calls in the (save-some-buffers) case, and they are the exact same as in the case where I save the buffer individually with “C-x C-s”. Despite (clang-format-buffer) doing apparently the same thing in both cases, with (save-some-buffers) something is moving window-start to the start of the file, which is not acceptable.

I don’t see a problem with clang-format.el to be fixed, and I don’t know how to proceed with this any more, so here I just wanted to give an account of my experience with this, in the hope that it could be useful.

What I’ve done to my clang-format.el for now is to remove the loop at the end of the function that restores the window-starts of the windows showing the formatted buffer. The result of that is still is slightly disorienting because the line containing the point is centered on the screen (if possible), but it’s far better than having the window-start moved to the first line.

Clang-formatting before save must be quite a common practice, so is anyone doing so not seeing the same window-start dislocation problem with (save-some-buffers)? If I can duplicate an emacs setup that doesn’t have this problem, that would help.

I have not heard of this problem before, but I am also not personally using emacs. Adding Johann Klähn, who has just proposed improvements to the emacs integration. Maybe he has experienced this problem, too.

I think the “right” solution here might be what we do for the vim integration. Instead of replacing the entire buffer, we just compute a diff and only apply the diff chunks individually. This makes fiddling with the window starts completely unnecessary.

I have a prototype[1] that does adjustments via single edit operations
based on the '-output-replacements-xml' option (instead of replacing
the whole buffer; this would be similar to the difflib-approach, I
guess?). But when using this option the JSON-header containing the
'-cursor' information is not returned, so I have to rely on markers
inserted into the buffer to keep the cursor position. On the upside
this allows me to track the cursor per-window.


Johann’s clang-format.el is now working great for me. For some reason, the XML library in my emacs 23.4 (from Debian wheezy) was complaining about multiple root tags in the XML from clang-format, but when I upgraded to emacs 24.4 that problem disappeared. It’s strange because a) there were not multiple root tags, and b) Johann tested with the same version of emacs from wheezy and that worked for him. Despite that little mystery, from my point of view all’s well that ends well.

For thoroughness, after upgrading my emacs, I also re-tested the clang-format.el from clang-format-3.6, and I still had the same problem with window-starts getting moved to the start of the buffer when doing “C-x s” (save-some-buffers).

Maybe Johann’s clang-format.el should be adopted into clang-format?

Yes, we are about to do that. I just need someone with actual elisp knowledge to review the patch ;-).