[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/go-mode e76464a 331/495: go.tools/oracle: an oracle that a
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/go-mode e76464a 331/495: go.tools/oracle: an oracle that answers questions about Go source code. |
Date: |
Sat, 7 Aug 2021 09:05:42 -0400 (EDT) |
branch: elpa/go-mode
commit e76464af5f772173fd211f798cc8bbd6c1030c1a
Author: Alan Donovan <adonovan@google.com>
Commit: Dominik Honnef <dominik@honnef.co>
go.tools/oracle: an oracle that answers questions about Go source code.
+ Tests.
+ Emacs integration.
+ Emacs integration test.
+ very rudimentary Vim integration. Needs some love from a Vim user.
TODO (in follow-ups):
- More tests would be good.
We'll need to make the output order deterministic in more places.
- Documentation.
R=gri, crawshaw, dominik.honnef
CC=golang-dev
https://golang.org/cl/9502043
---
guru_import/cmd/oracle/oracle.el | 180 +++++++++++++++++++++++++++++++++++++++
1 file changed, 180 insertions(+)
diff --git a/guru_import/cmd/oracle/oracle.el b/guru_import/cmd/oracle/oracle.el
new file mode 100644
index 0000000..4cae84f
--- /dev/null
+++ b/guru_import/cmd/oracle/oracle.el
@@ -0,0 +1,180 @@
+;;;
+;;; Integration of the Go 'oracle' analysis tool into Emacs.
+;;;
+;;; To install the Go oracle, run:
+;;; % export GOROOT=... GOPATH=...
+;;; % go get code.google.com/p/go.tools/cmd/oracle
+;;; % mv $GOPATH/bin/oracle $GOROOT/bin/
+;;;
+;;; Load this file into Emacs and set go-oracle-scope to your
+;;; configuration. Then, find a file of Go source code, select an
+;;; expression of interest, and press F4 (for "describe") or run one
+;;; of the other go-oracle-xxx commands.
+;;;
+;;; TODO(adonovan): simplify installation and configuration by making
+;;; oracle a subcommand of 'go tool'.
+
+(require 'compile)
+(require 'go-mode)
+(require 'cl)
+
+(defgroup go-oracle nil
+ "Options specific to the Go oracle."
+ :group 'go)
+
+(defcustom go-oracle-command (concat (car (go-root-and-paths)) "/bin/oracle")
+ "The Go oracle command; the default is $GOROOT/bin/oracle."
+ :type 'string
+ :group 'go-oracle)
+
+(defcustom go-oracle-scope ""
+ "The scope of the analysis. See `go-oracle-set-scope'."
+ :type 'string
+ :group 'go-oracle)
+
+(defvar go-oracle--scope-history
+ nil
+ "History of values supplied to `go-oracle-set-scope'.")
+
+(defun go-oracle-set-scope ()
+ "Sets the scope for the Go oracle, prompting the user to edit the
+previous scope.
+
+The scope specifies a set of arguments, separated by spaces.
+It may be:
+1) a set of packages whose main() functions will be analyzed.
+2) a list of *.go filenames; they will treated like as a single
+ package (see #3).
+3) a single package whose main() function and/or Test* functions
+ will be analyzed.
+
+In the common case, this is similar to the argument(s) you would
+specify to 'go build'."
+ (interactive)
+ (let ((scope (read-from-minibuffer "Go oracle scope: "
+ go-oracle-scope
+ nil
+ nil
+ 'go-oracle--scope-history)))
+ (if (string-equal "" scope)
+ (error "You must specify a non-empty scope for the Go oracle"))
+ (setq go-oracle-scope scope)))
+
+(defun go-oracle--run (mode)
+ "Run the Go oracle in the specified MODE, passing it the
+selected region of the current buffer. Process the output to
+replace each file name with a small hyperlink. Display the
+result."
+ (if (not buffer-file-name)
+ (error "Cannot use oracle on a buffer without a file name"))
+ ;; It's not sufficient to save a modified buffer since if
+ ;; gofmt-before-save is on the before-save-hook, saving will
+ ;; disturb the selected region.
+ (if (buffer-modified-p)
+ (error "Please save the buffer before invoking go-oracle"))
+ (if (string-equal "" go-oracle-scope)
+ (go-oracle-set-scope))
+ (let* ((filename (file-truename buffer-file-name))
+ (pos (if (use-region-p)
+ (format "%s-%s"
+ (1- (go--position-bytes (region-beginning)))
+ (1- (go--position-bytes (region-end))))
+ (format "%s" (1- (position-bytes (point))))))
+ ;; This would be simpler if we could just run 'go tool oracle'.
+ (env-vars (go-root-and-paths))
+ (goroot-env (concat "GOROOT=" (car env-vars)))
+ (gopath-env (concat "GOPATH=" (mapconcat #'identity (cdr env-vars)
":"))))
+ (with-current-buffer (get-buffer-create "*go-oracle*")
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (insert "Go Oracle\n")
+ (let ((args (append (list go-oracle-command nil t nil
+ "-ptalog=" ; avoid writing the huge log
+ (format "-pos=%s %s" filename pos)
+ (format "-mode=%s" mode))
+ (split-string go-oracle-scope " " t))))
+ ;; Log the command to *Messages*, for debugging.
+ (message "Command: %s:" args)
+ (message nil) ; clears/shrinks minibuffer
+
+ (message "Running oracle...")
+ ;; Use dynamic binding to modify/restore the environment
+ (let ((process-environment (list* goroot-env gopath-env
"CGO_ENABLED=0" process-environment)))
+ (apply #'call-process args)))
+ (insert "\n")
+ (compilation-mode)
+ (setq compilation-error-screen-columns nil)
+ (let ((w (display-buffer (current-buffer))))
+ (balance-windows)
+ (shrink-window-if-larger-than-buffer w)
+ (set-window-point w (point-min)))
+
+ ;; Hide the file/line info to save space.
+ ;; Replace each with a little widget.
+ ;; compilation-mode + this loop = slooow.
+ ;; TODO(adonovan): have oracle give us an S-expression
+ ;; and we'll do the markup directly.
+ (let ((buffer-read-only nil)
+ (p 1))
+ (while (not (null p))
+ (let ((np (compilation-next-single-property-change p
'compilation-message)))
+ (message "Post-processing link (%d%%)" (/ (* p 100) (point-max)))
+ (if np
+ (when (equal (line-number-at-pos p) (line-number-at-pos np))
+ ;; np is (typically) the space following ":"; consume it too.
+ (put-text-property p np 'display "▶")
+ (goto-char np)
+ (insert " ")))
+ (setq p np)))
+ (message nil)))))
+
+(defun go-oracle-callees ()
+ "Show possible callees of the function call at the current point."
+ (interactive)
+ (go-oracle--run "callees"))
+
+(defun go-oracle-callers ()
+ "Show the set of callers of the function containing the current point."
+ (interactive)
+ (go-oracle--run "callers"))
+
+(defun go-oracle-callgraph ()
+ "Show the callgraph of the current program."
+ (interactive)
+ (go-oracle--run "callgraph"))
+
+(defun go-oracle-callstack ()
+ "Show an arbitrary path from a root of the call graph to the
+function containing the current point."
+ (interactive)
+ (go-oracle--run "callstack"))
+
+(defun go-oracle-describe ()
+ "Describe the expression at the current point."
+ (interactive)
+ (go-oracle--run "describe"))
+
+(defun go-oracle-implements ()
+ "Describe the 'implements' relation for types in the package
+containing the current point."
+ (interactive)
+ (go-oracle--run "implements"))
+
+(defun go-oracle-freevars ()
+ "Enumerate the free variables of the current selection."
+ (interactive)
+ (go-oracle--run "freevars"))
+
+(defun go-oracle-channel-peers ()
+ "Enumerate the set of possible corresponding sends/receives for
+this channel receive/send operation."
+ (interactive)
+ (go-oracle--run "peers"))
+
+;; TODO(adonovan): don't mutate the keymap; just document how users
+;; can do this themselves. But that means freezing the API, so don't
+;; do that yet; wait till v1.0.
+(add-hook 'go-mode-hook
+ #'(lambda () (local-set-key (kbd "<f4>") #'go-oracle-describe)))
+
+(provide 'go-oracle)
- [nongnu] elpa/go-mode f12f2cc 319/495: Add support for gogetdoc, (continued)
- [nongnu] elpa/go-mode f12f2cc 319/495: Add support for gogetdoc, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 7fec5b2 317/495: Move test Go files to testdata, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 648ad3d 311/495: Use null-device instead of /dev/null, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode e035e60 309/495: Mention GOPATH detection in README, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 43da263 313/495: Simplify go-root-and-paths by using process-lines, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 95c74ba 324/495: Update URL to gogetdoc tool., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 228ded4 314/495: Use cons instead of append, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 205672f 322/495: Use separate godoc commands for godoc and godoc-at-point, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 737611e 329/495: Update URL to goimports, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode b65e408 334/495: go.tools/cmd/oracle: cosmetic tweaks to Emacs., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode e76464a 331/495: go.tools/oracle: an oracle that answers questions about Go source code.,
ELPA Syncer <=
- [nongnu] elpa/go-mode 8560557 354/495: cmd/guru: fix bug in mode map caused by bad merge, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode b36d2fd 352/495: cmd/guru: emacs: report an error when the guru command fails, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode d41ebaf 341/495: go.tools/oracle: improvements to command set and performance., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 385153c 338/495: go.tools/oracle: new query 'referrers' returns all references to an identifier., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode f18b4eb 369/495: cmd/guru: support streaming plain and -json output, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 9a5284b 362/495: cmd/guru: emacs: update scope documentation, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 4dfa1c4 350/495: cmd/guru: add support for loading modified files, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode fdb5dfa 335/495: go.tools/oracle: change notation for byte offsets to "-pos=file.go:#123-#456", ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 1dc6fb5 357/495: cmd/guru: fix mode map, again, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode fac4a24 336/495: go.tools/importer: negate "cgo" build tag to avoid native code in "net"., ELPA Syncer, 2021/08/07