Commits

Mats Lidell  committed 5d9b54f

go-mode synced with upstream version 13677

  • Participants
  • Parent commits 2ced404

Comments (0)

Files changed (2)

+2012-08-17  Mats Lidell  <matsl@xemacs.org>
+
+	* go-mode.el: Sync with upstream version 13677
+
 2012-05-14  Norbert Koch  <viteno@xemacs.org>
 
 	* Makefile (VERSION): XEmacs package 2.26 released.
 ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-;;; Synced up with: upstream go-mode.el 13182:9d6693456f93
+;;; Synced up with: upstream go-mode.el 13677:c5f564efc620
 
 ;;; Commentary:
 
 marked from the beginning up to this point.")
 (make-variable-buffer-local 'go-mode-mark-nesting-end)
 
+(defun go-mode-mark-clear-cs (b e l)
+  "An after-change-function that removes the go-mode-cs text property"
+  (remove-text-properties b e '(go-mode-cs)))
+
 (defun go-mode-mark-clear-cache (b e)
   "A before-change-function that clears the comment/string and
 nesting caches from the modified point on."
 	(remove-text-properties
 	 b (min go-mode-mark-string-end (point-max)) '(go-mode-comment nil))
 	(setq go-mode-mark-comment-end b)))
-    
+
     (when (< b go-mode-mark-nesting-end)
       (remove-text-properties b (min go-mode-mark-nesting-end (point-max)) '(go-mode-nesting nil))
       (setq go-mode-mark-nesting-end b))))
 
   (unless pos
     (setq pos (point)))
-  (when (> pos go-mode-mark-cs-end)
-    (go-mode-mark-cs pos))
+  (when (>= pos go-mode-mark-cs-end)
+    (go-mode-mark-cs (1+ pos)))
   (get-text-property pos 'go-mode-cs))
 
 (defun go-mode-mark-cs (end)
 	    ;; Back up to the last known state.
 	    (let ((last-cs
 		   (and (> go-mode-mark-cs-end 1)
-			(get-text-property (1- go-mode-mark-cs-end) 
+			(get-text-property (1- go-mode-mark-cs-end)
 					   'go-mode-cs))))
 	      (if last-cs
 		  (car last-cs)
 	    ;; Back up to the last known state.
 	    (let ((last-comment
 		   (and (> go-mode-mark-comment-end 1)
-			(get-text-property (1- go-mode-mark-comment-end) 
+			(get-text-property (1- go-mode-mark-comment-end)
 					   'go-mode-comment))))
 	      (if last-comment
 		  (car last-comment)
 	    ;; Back up to the last known state.
 	    (let ((last-cs
 		   (and (> go-mode-mark-string-end 1)
-			(get-text-property (1- go-mode-mark-string-end) 
+			(get-text-property (1- go-mode-mark-string-end)
 					   'go-mode-string))))
 	      (if last-cs
 		  (car last-cs)
        (while (< pos end)
 	 (goto-char pos)
 	 (let ((cs-end			; end of the text property
-		(cond 
+		(cond
 		 ((looking-at "\"")
 		  (goto-char (1+ pos))
 		  (if (looking-at "[^\"\n\\\\]*\\(\\\\.[^\"\n\\\\]*\\)*\"")
       (cond
        ((and cs (save-excursion
                   (goto-char (car cs))
-                  (looking-at "\\s\"")))
+                  (looking-at "`")))
         ;; Inside a multi-line string.  Don't mess with indentation.
         nil)
        (cs
   ;; Remove stale text properties
   (save-restriction
     (widen)
-    (remove-text-properties 1 (point-max)
-                            '(go-mode-cs nil go-mode-nesting nil)))
+    (let ((modified (buffer-modified-p)))
+      (remove-text-properties 1 (point-max)
+                              '(go-mode-cs nil go-mode-nesting nil))
+      ;; remove-text-properties marks the buffer modified. undo that if it
+      ;; wasn't originally marked modified.
+      (set-buffer-modified-p modified)))
 
   ;; Reset the syntax mark caches
   (setq go-mode-mark-cs-end      1
         go-mode-mark-nesting-end 1)
   (add-hook 'before-change-functions #'go-mode-mark-clear-cache nil t)
+  (add-hook 'after-change-functions #'go-mode-mark-clear-cs nil t)
 
   ;; Indentation
   (set (make-local-variable 'indent-line-function)
   (set (make-local-variable 'comment-end)   "")
 
   ;; Go style
-  (setq indent-tabs-mode t))
+  (setq indent-tabs-mode t)
+
+  ;; Handle unit test failure output in compilation-mode
+  ;;
+  ;; Note the final t argument to add-to-list for append, ie put these at the
+  ;; *ends* of compilation-error-regexp-alist[-alist]. We want go-test to be
+  ;; handled first, otherwise other elements will match that don't work, and
+  ;; those alists are traversed in *reverse* order:
+  ;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-12/msg00674.html
+  (when (and (boundp 'compilation-error-regexp-alist)
+           (boundp 'compilation-error-regexp-alist-alist))
+      (add-to-list 'compilation-error-regexp-alist 'go-test t)
+      (add-to-list 'compilation-error-regexp-alist-alist
+                   '(go-test . ("^\t+\\([^()\t\n]+\\):\\([0-9]+\\):? .*$" 1 2)) t)))
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist (cons "\\.go$" #'go-mode))
 
   (interactive)
   (let ((currconf (current-window-configuration)))
-    (let ((srcbuf (current-buffer)))
-      (with-temp-buffer
-        (let ((outbuf (current-buffer))
-              (errbuf (get-buffer-create "*Gofmt Errors*"))
+    (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*"))
               (coding-system-for-read 'utf-8)    ;; use utf-8 with subprocesses
               (coding-system-for-write 'utf-8))
-          (with-current-buffer errbuf (erase-buffer))
+          (with-current-buffer errbuf
+            (toggle-read-only 0)
+            (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))
-                    ;; restore window config
-                    ;; gofmt succeeded: replace the current buffer with outbuf,
-                    ;; restore the mark and point, and discard errbuf.
-                    (let ((old-mark (mark t))
-                          (old-point (point))
-                          (old-start (window-start)))
-                      (erase-buffer)
-                      (insert-buffer-substring outbuf)
-                      (set-window-configuration currconf)
-                      (set-window-start (selected-window) (min old-start (point-max)))
-                      (goto-char (min old-point (point-max)))
-                      (if old-mark (push-mark (min old-mark (point-max)) t))
-                      (kill-buffer errbuf))
+                ; 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")))
+                  (if (= 0 (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
-                  (display-buffer errbuf)))))
+                  (gofmt-process-errors filename errbuf))))))
 
           ;; Collapse any window opened on outbuf if shell-command-on-region
           ;; displayed it.
-          (delete-windows-on outbuf))))))
+          (delete-windows-on patchbuf)))
+      (kill-buffer patchbuf))))
+
+(defun gofmt-replace-buffer (srcbuf patchbuf)
+  (with-current-buffer srcbuf
+    (erase-buffer)
+    (insert-buffer-substring patchbuf)))
+
+(defconst gofmt-stdin-tag "<standard input>")
+
+(defun gofmt-apply-patch (filename srcbuf patchbuf)
+  (require 'diff-mode)
+  ;; apply all the patch hunks
+  (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))
+      ;; When there's no more hunks, diff-hunk-next signals an error, ignore it
+      (error nil))))
+
+(defun gofmt-process-errors (filename 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))
+    (display-buffer errbuf)
+    (compilation-mode)))
 
 ;;;###autoload
 (defun gofmt-before-save ()