misc/emacs: gofmt: don't clobber the current buffer on failure

Change M-x gofmt to display errors in a new buffer instead of
clobbering the current buffer.

Add gofmt-before-save, which runs gofmt when in go-mode.  This
can be used with before-save-hook.  Add to your .emacs:
  (add-hook 'before-save-hook 'gofmt-before-save)

R=rsc, aclements, amdragon
CC=golang-dev
https://golang.org/cl/4276059
diff --git a/misc/emacs/go-mode-load.el b/misc/emacs/go-mode-load.el
index c731563..0ace46d 100644
--- a/misc/emacs/go-mode-load.el
+++ b/misc/emacs/go-mode-load.el
@@ -18,10 +18,11 @@
 ;;   (let ((generated-autoload-file buffer-file-name)) (update-file-autoloads "go-mode.el"))
 
 
-;;;### (autoloads (go-mode) "go-mode" "go-mode.el" (19168 32439))
+;;;### (autoloads (gofmt-before-save gofmt go-mode) "go-mode" "go-mode.el"
+;;;;;;  (19847 61431))
 ;;; Generated autoloads from go-mode.el
 
-(autoload (quote go-mode) "go-mode" "\
+(autoload 'go-mode "go-mode" "\
 Major mode for editing Go source text.
 
 This provides basic syntax highlighting for keywords, built-ins,
@@ -30,7 +31,19 @@
 
 \(fn)" t nil)
 
-(add-to-list (quote auto-mode-alist) (cons "\\.go$" (function go-mode)))
+(add-to-list 'auto-mode-alist (cons "\\.go$" #'go-mode))
+
+(autoload 'gofmt "go-mode" "\
+Pipe the current buffer through the external tool `gofmt`.
+Replace the current buffer on success; display errors on failure.
+
+\(fn)" t nil)
+
+(autoload 'gofmt-before-save "go-mode" "\
+Add this to .emacs to run gofmt on the current buffer when saving:
+ (add-hook 'before-save-hook #'gofmt-before-save)
+
+\(fn)" t nil)
 
 ;;;***
 
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index 2624e87..692cabf 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -498,21 +498,45 @@
   (require 'go-mode)
   (go-mode))
 
-(provide 'go-mode)
-
+;;;###autoload
 (defun gofmt ()
-  "Pipe the current buffer through the external tool `gofmt`."
-  
-  (interactive)
-  ;; for some reason save-excursion isn't working
-  ;; probably because shell-command-on-region deletes the contents of the
-  ;; region before filling in the new values
-  ;; so we will save the point/mark by hand
-  ;; similarly we can't use push-mark/pop-mark
-  (let ((old-mark (mark t)) (old-point (point)))
-    (save-restriction
-      (let (deactivate-mark)
-        (widen)
-        (shell-command-on-region (point-min) (point-max) "gofmt" t t shell-command-default-error-buffer)))
-    (goto-char (min old-point (point-max)))
-    (if old-mark (set-mark (min old-mark (point-max))))))
+ "Pipe the current buffer through the external tool `gofmt`.
+Replace the current buffer on success; display errors on failure."
+
+ (interactive)
+ (let ((srcbuf (current-buffer)))
+   (with-temp-buffer
+     (let ((outbuf (current-buffer))
+           (errbuf (get-buffer-create "*Gofmt Errors*")))
+       (with-current-buffer errbuf (erase-buffer))
+       (with-current-buffer srcbuf
+         (save-restriction
+           (let (deactivate-mark)
+             (widen)
+             (if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt"
+                                               outbuf nil errbuf))
+                 ;; gofmt succeeded: replace the current buffer with outbuf,
+                 ;; restore the mark and point, and discard errbuf.
+                 (let ((old-mark (mark t)) (old-point (point)))
+                   (erase-buffer)
+                   (insert-buffer-substring outbuf)
+                   (goto-char (min old-point (point-max)))
+                   (if old-mark (set-mark (min old-mark (point-max))))
+                   (kill-buffer errbuf))
+
+               ;; gofmt failed: display the errors
+               (display-buffer errbuf)))))
+
+       ;; Collapse any window opened on outbuf if shell-command-on-region
+       ;; displayed it.
+       (delete-windows-on outbuf)))))
+
+;;;###autoload
+(defun gofmt-before-save ()
+ "Add this to .emacs to run gofmt on the current buffer when saving:
+ (add-hook 'before-save-hook #'gofmt-before-save)"
+
+ (interactive)
+ (when (eq major-mode 'go-mode) (gofmt)))
+
+(provide 'go-mode)