emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/go-mode 856eff3 105/495: Instead of relying on gofmt's -d


From: ELPA Syncer
Subject: [nongnu] elpa/go-mode 856eff3 105/495: Instead of relying on gofmt's -d flag, use diff -n directly. This
Date: Sat, 7 Aug 2021 09:04:53 -0400 (EDT)

branch: elpa/go-mode
commit 856eff3eafaa04fa6d1d54fbc1fd06558449e21a
Author: Dominik Honnef <dominikh@fork-bomb.org>
Commit: Dominik Honnef <dominikh@fork-bomb.org>

    Instead of relying on gofmt's -d flag, use diff -n directly. This
    allows us to implement our own patch function instead of having to use
    diff-mode.
    
    This fixes two issues:
    
    - no more skipping over changes
    - no more problems with whitespace in file names
---
 go-mode.el | 149 +++++++++++++++++++++++++------------------------------------
 1 file changed, 62 insertions(+), 87 deletions(-)

diff --git a/go-mode.el b/go-mode.el
index 4b0de54..8d65fe9 100644
--- a/go-mode.el
+++ b/go-mode.el
@@ -5,13 +5,11 @@
 ;; license that can be found in the LICENSE file.
 
 (require 'cl)
-(require 'diff-mode)
 (require 'ffap)
 (require 'find-lisp)
 (require 'url)
 
 (defconst go-dangling-operators-regexp "[^-]-\\|[^+]\\+\\|[/*&><.=|^]")
-(defconst gofmt-stdin-tag "<standard input>")
 (defconst go-identifier-regexp "[[:word:][:multibyte:]_]+")
 (defconst go-label-regexp go-identifier-regexp)
 (defconst go-type-regexp "[[:word:][:multibyte:]_*]+")
@@ -360,99 +358,76 @@ recommended that you look at goflymake
 ;;;###autoload
 (add-to-list 'auto-mode-alist (cons "\\.go\\'" 'go-mode))
 
+(defun go--apply-rcs-patch (patch-buffer)
+  (let ((target-buffer (current-buffer))
+        (line-offset 0))
+    (save-excursion
+      (with-current-buffer patch-buffer
+        (goto-char (point-min))
+        (while (not (eobp))
+          (unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)")
+            (error "invalid rcs patch or internal error in 
go--apply-rcs-patch"))
+          (forward-line)
+          (let ((action (match-string 1))
+                (from (string-to-number (match-string 2)))
+                (len  (string-to-number (match-string 3))))
+            (cond
+             ((equal action "a")
+              (let ((start (point)))
+                (forward-line len)
+                (let ((text (buffer-substring start (point))))
+                  (with-current-buffer target-buffer
+                    (decf line-offset len)
+                    (goto-char (point-min))
+                    (forward-line (- from len line-offset))
+                    (insert text)))))
+             ((equal action "d")
+              (with-current-buffer target-buffer
+                (goto-char (point-min))
+                (forward-line (- from line-offset 1))
+                (incf line-offset len)
+                (kill-whole-line len)))
+             (t
+              (error "invalid rcs patch or internal error in 
go--apply-rcs-patch")))))))))
+
 (defun gofmt ()
-  "Pipe the current buffer through the external tool `gofmt`.
-Replace the current buffer on success; display errors on failure."
+  "Formats the current buffer according to the gofmt tool."
 
   (interactive)
-  (let ((currconf (current-window-configuration)))
-    (let ((srcbuf (current-buffer))
-          (filename buffer-file-name)
-          (patchbuf (get-buffer-create "*Gofmt patch*")))
-      (with-current-buffer patchbuf
-        (let ((errbuf (get-buffer-create "*Gofmt Errors*"))
-              ;; use utf-8 with subprocesses
-              (coding-system-for-read 'utf-8)
-              (coding-system-for-write 'utf-8))
-          (with-current-buffer errbuf
-            (setq buffer-read-only nil)
-            (erase-buffer))
-          (with-current-buffer srcbuf
-            (save-restriction
-              (let (deactivate-mark)
-                (widen)
-                ;; If this is a new file, diff-mode can't apply a
-                ;; patch to a non-exisiting file, so replace the buffer
-                ;; completely with the output of 'gofmt'.
-                ;; If the file exists, patch it to keep the 'undo' list happy.
-                (let* ((newfile (not (file-exists-p filename)))
-                       (flag (if newfile "" " -d")))
-
-                  ;; diff-mode doesn't work too well with missing
-                  ;; end-of-file newline, so add one
-                  (if (/= (char-after (1- (point-max))) ?\n)
-                      (save-excursion
-                        (goto-char (point-max))
-                        (insert ?\n)))
-
-                  (if (zerop (shell-command-on-region (point-min) (point-max)
-                                                      (concat "gofmt" flag)
-                                                      patchbuf nil errbuf))
-                      ;; gofmt succeeded: replace buffer or apply patch hunks.
-                      (let ((old-point (point))
-                            (old-mark (mark t)))
-                        (kill-buffer errbuf)
-                        (if newfile
-                            ;; New file, replace it (diff-mode won't work)
-                            (gofmt--replace-buffer srcbuf patchbuf)
-                          ;; Existing file, patch it
-                          (gofmt--apply-patch filename srcbuf patchbuf))
-                        (goto-char (min old-point (point-max)))
-                        ;; Restore the mark and point
-                        (if old-mark (push-mark (min old-mark (point-max)) t))
-                        (set-window-configuration currconf))
-
-                    ;; gofmt failed: display the errors
-                    (message "Could not apply gofmt. Check errors for details")
-                    (gofmt--process-errors filename errbuf))))))
-
-          ;; Collapse any window opened on outbuf if shell-command-on-region
-          ;; displayed it.
-          (delete-windows-on patchbuf)))
-      (kill-buffer patchbuf))))
-
-(defun gofmt--replace-buffer (srcbuf patchbuf)
-  (with-current-buffer srcbuf
-    (erase-buffer)
-    (insert-buffer-substring patchbuf))
-  (message "Applied gofmt"))
-
-(defun gofmt--apply-patch (filename srcbuf patchbuf)
-  ;; apply all the patch hunks
-  (let (changed)
+  (let ((tmpfile (make-temp-file "gofmt" nil ".go"))
+        (patchbuf (get-buffer-create "*Gofmt patch*"))
+        (errbuf (get-buffer-create "*Gofmt Errors*"))
+        (coding-system-for-read 'utf-8)
+        (coding-system-for-write 'utf-8))
+
+    (with-current-buffer errbuf
+      (setq buffer-read-only nil)
+      (erase-buffer))
     (with-current-buffer patchbuf
-      (goto-char (point-min))
-      ;; The .* is for TMPDIR, but to avoid dealing with TMPDIR
-      ;; having a trailing / or not, it's easier to just search for .*
-      ;; especially as we're only replacing the first instance.
-      (if (re-search-forward "^--- \\(.*/gofmt[0-9]*\\)" nil t)
-          (replace-match filename nil nil nil 1))
-      (condition-case nil
-          (while t
-            (diff-hunk-next)
-            (diff-apply-hunk)
-            (setq changed t))
-        ;; When there's no more hunks, diff-hunk-next signals an error, ignore 
it
-        (error nil)))
-    (if changed (message "Applied gofmt") (message "Buffer was already 
gofmted"))))
-
-(defun gofmt--process-errors (filename errbuf)
+      (erase-buffer))
+
+    (write-region nil nil tmpfile)
+    (if (zerop (shell-command (concat "gofmt -w " (shell-quote-argument 
tmpfile)) nil errbuf))
+        (progn
+          (if (zerop (shell-command-on-region (point-min) (point-max) (concat 
"diff -n - " (shell-quote-argument tmpfile)) patchbuf))
+              (message "Buffer is already gofmted")
+            (go--apply-rcs-patch patchbuf)
+            (kill-buffer errbuf)
+            (message "Applied gofmt")))
+      (message "Could not apply gofmt. Check errors for details")
+      (gofmt--process-errors (buffer-file-name) tmpfile errbuf))
+
+    (kill-buffer patchbuf)
+    (delete-file tmpfile)))
+
+
+(defun gofmt--process-errors (filename tmpfile errbuf)
   ;; Convert the gofmt stderr to something understood by the compilation mode.
   (with-current-buffer errbuf
     (goto-char (point-min))
     (insert "gofmt errors:\n")
-    (if (search-forward gofmt-stdin-tag nil t)
-        (replace-match (file-name-nondirectory filename) nil t))
+    (while (search-forward-regexp (concat "^\\(" (regexp-quote tmpfile) 
"\\):") nil t)
+      (replace-match (file-name-nondirectory filename) t t nil 1))
     (display-buffer errbuf)
     (compilation-mode)))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]