summaryrefslogtreecommitdiff
path: root/misc/emacs/go-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'misc/emacs/go-mode.el')
-rw-r--r--misc/emacs/go-mode.el151
1 files changed, 110 insertions, 41 deletions
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index 33ee7022f..214c19685 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -33,8 +33,8 @@
;; Operators (punctuation)
(modify-syntax-entry ?+ "." st)
(modify-syntax-entry ?- "." st)
- (modify-syntax-entry ?* "." st)
- (modify-syntax-entry ?/ "." st)
+ (modify-syntax-entry ?* ". 23" st) ; also part of comments
+ (modify-syntax-entry ?/ (if (featurep 'xemacs) ". 1456" ". 124b") st) ; ditto
(modify-syntax-entry ?% "." st)
(modify-syntax-entry ?& "." st)
(modify-syntax-entry ?| "." st)
@@ -50,6 +50,9 @@
(modify-syntax-entry ?` "." st)
(modify-syntax-entry ?\\ "." st)
+ ;; Newline is a comment-ender.
+ (modify-syntax-entry ?\n "> b" st)
+
st)
"Syntax table for Go mode.")
@@ -179,6 +182,10 @@ to and including character (1- go-mode-mark-comment-end)).")
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."
@@ -243,8 +250,8 @@ comment or string."
(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)
@@ -435,7 +442,7 @@ if no further tokens of the type exist."
(when (search-forward "\n" (cdr cs) t)
(put-text-property
(car cs) (cdr cs) 'font-lock-multline t))
- (set-match-data (list (car cs) (cdr cs) (current-buffer)))
+ (set-match-data (list (car cs) (copy-marker (cdr cs))))
(goto-char (cdr cs))
(setq result t))
;; Wrong type. Look for next comment/string after this one.
@@ -545,8 +552,9 @@ token on the line."
(not (looking-at go-mode-non-terminating-keywords-regexp)))))))
(defun go-mode-whitespace-p (char)
- "Is char whitespace in the syntax table for go."
- (eq 32 (char-syntax char)))
+ "Is newline, or char whitespace in the syntax table for go."
+ (or (eq char ?\n)
+ (= (char-syntax char) ?\ )))
(defun go-mode-backward-skip-comments ()
"Skip backward over comments and whitespace."
@@ -589,7 +597,7 @@ indented one level."
(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
@@ -698,13 +706,18 @@ functions, and some types. It also provides indentation that is
;; 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)
@@ -716,7 +729,20 @@ functions, and some types. It also provides indentation that is
(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))
@@ -737,36 +763,79 @@ Replace the current buffer on success; display errors on failure."
(interactive)
(let ((currconf (current-window-configuration)))
- (let ((srcbuf (current-buffer)))
- (with-temp-buffer
- (let ((outbuf (current-buffer))
- (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 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)))
- (set-window-configuration currconf)
- (erase-buffer)
- (insert-buffer-substring outbuf)
- (goto-char (min old-point (point-max)))
- (if old-mark (push-mark (min old-mark (point-max)) t))
- (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))))))
+ (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
+ (toggle-read-only 0)
+ (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")))
+ (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
+ (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)))
+
+(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
+ (replace-regexp "^--- /tmp/gofmt[0-9]*" (concat "--- " filename)
+ nil (point-min) (point-max))
+ (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
+ (beginning-of-buffer)
+ (insert "gofmt errors:\n")
+ (replace-string gofmt-stdin-tag (file-name-nondirectory filename) nil (point-min) (point-max))
+ (display-buffer errbuf)
+ (compilation-mode)))
;;;###autoload
(defun gofmt-before-save ()