]> Cypherpunks repositories - gostls13.git/commitdiff
misc/emacs: Add support for godef
authorDominik Honnef <dominik.honnef@gmail.com>
Tue, 19 Mar 2013 15:29:28 +0000 (11:29 -0400)
committerAlan Donovan <adonovan@google.com>
Tue, 19 Mar 2013 15:29:28 +0000 (11:29 -0400)
godef[1][2] is a third party tool for printing information about
expressions, especially the location of their definition. This can be
used to implement a "jump to definition" function. Unlike
cross-language solutions like ctags, godef does not require an index,
operates on the Go AST instead of symbols and works across packages,
including the standard library.

This patch implements two new public functions: godef-describe (C-c
C-d) and godef-jump (C-d C-j). godef-describe describes the expression
at point, printing its type, and godef-jump jumps to its definition.

[1]: https://code.google.com/p/rog-go/source/browse/exp/cmd/godef/
[2]: go get code.google.com/p/rog-go/exp/cmd/godef

R=adonovan, cw, patrick.allen.higgins, sameer
CC=golang-dev
https://golang.org/cl/7781043

misc/emacs/go-mode.el

index b1dd0d5d9c6cb081100c830e5df99998103ab00f..93e2a6867390584cd1dcc64148261d5494f53297 100644 (file)
@@ -15,6 +15,8 @@
 ;;   - Functions that could be backported but won't because 21.5.32
 ;;     covers them: plenty.
 ;;   - Features that are still partly broken:
+;;     - godef will not work correctly if multibyte characters are
+;;       being used
 ;;     - Fontification will not handle unicode correctly
 ;;
 ;; - Do not use \_< and \_> regexp delimiters directly; use
     (define-key m ":" 'go-mode-insert-and-indent)
     (define-key m "=" 'go-mode-insert-and-indent)
     (define-key m (kbd "C-c C-a") 'go-import-add)
+    (define-key m (kbd "C-c C-j") 'godef-jump)
+    (define-key m (kbd "C-c C-d") 'godef-describe)
     m)
   "Keymap used by Go mode to implement electric keys.")
 
@@ -391,12 +395,26 @@ The following extra functions are defined:
 - `go-goto-imports'
 - `go-play-buffer' and `go-play-region'
 - `go-download-play'
+- `godef-describe' and `godef-jump'
 
 If you want to automatically run `gofmt' before saving a file,
 add the following hook to your emacs configuration:
 
 \(add-hook 'before-save-hook 'gofmt-before-save)
 
+If you want to use `godef-jump' instead of etags (or similar),
+consider binding godef-jump to `M-.', which is the default key
+for `find-tag':
+
+\(add-hook 'go-mode-hook (lambda ()
+                          (local-set-key (kbd \"M-.\") 'godef-jump)))
+
+Please note that godef is an external dependency. You can install
+it with
+
+go get code.google.com/p/rog-go/exp/cmd/godef
+
+
 If you're looking for even more integration with Go, namely
 on-the-fly syntax checking, auto-completion and snippets, it is
 recommended that you look at goflymake
@@ -823,4 +841,59 @@ will be commented, otherwise they will be removed completely."
         (message "Removed %d imports" (length lines)))
       (if flymake-state (flymake-mode-on)))))
 
+(defun godef--find-file-line-column (specifier)
+  "Given a file name in the format of `filename:line:column',
+visit FILENAME and go to line LINE and column COLUMN."
+  (let* ((components (split-string specifier ":"))
+         (line (string-to-number (nth 1 components)))
+         (column (string-to-number (nth 2 components))))
+    (with-current-buffer (find-file (car components))
+      (goto-char (point-min))
+      (forward-line (1- line))
+      (beginning-of-line)
+      (forward-char (1- column))
+      (if (buffer-modified-p)
+          (message "Buffer is modified, file position might not have been correct")))))
+
+(defun godef--call (point)
+  "Call godef, acquiring definition position and expression
+description at POINT."
+  (if (go--xemacs-p)
+      (message "godef does not reliably work in XEmacs, expect bad results"))
+  (if (not buffer-file-name)
+      (message "Cannot use godef on a buffer without a file name")
+    (let ((outbuf (get-buffer-create "*godef*")))
+      (with-current-buffer outbuf
+        (erase-buffer))
+      (call-process-region (point-min) (point-max) "godef" nil outbuf nil "-i" "-t" "-f" (file-truename buffer-file-name) "-o" (number-to-string (go--position-bytes (point))))
+      (with-current-buffer outbuf
+        (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n")))))
+
+(defun godef-describe (point)
+  "Describe the expression at POINT."
+  (interactive "d")
+  (condition-case nil
+      (let ((description (nth 1 (godef--call point))))
+        (if (string= "" description)
+            (message "No description found for expression at point")
+          (message "%s" description)))
+    (file-error (message "Could not run godef binary"))))
+
+(defun godef-jump (point)
+  "Jump to the definition of the expression at POINT."
+  (interactive "d")
+  (condition-case nil
+      (let ((file (car (godef--call point))))
+        (cond
+         ((string= "-" file)
+          (message "godef: expression is not defined anywhere"))
+         ((string= "godef: no identifier found" file)
+          (message "%s" file))
+         ((go--string-prefix-p "godef: no declaration found for " file)
+          (message "%s" file))
+         (t
+          (push-mark)
+          (godef--find-file-line-column file))))
+    (file-error (message "Could not run godef binary"))))
+
 (provide 'go-mode)