├── .gitignore
├── .travis.yml
├── Cask
├── Changes
├── Makefile
├── README.md
├── go-impl.el
├── image
└── go-impl.gif
└── test
└── test-go-impl.el
/.gitignore:
--------------------------------------------------------------------------------
1 | /.cask/
2 | *.elc
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: go
3 | go:
4 | - "1.6"
5 | - "tip"
6 | env:
7 | - EVM_EMACS=emacs-24.4-travis
8 | - EVM_EMACS=emacs-24.5-travis
9 | - EVM_EMACS=emacs-25.1-travis
10 | before_install:
11 | - go get -u golang.org/x/tools/cmd/godoc
12 | - export PATH=$HOME/gopath/bin:$PATH
13 | - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh
14 | - evm install $EVM_EMACS --use --skip
15 | - cask
16 | script:
17 | - go version
18 | - make test
19 |
--------------------------------------------------------------------------------
/Cask:
--------------------------------------------------------------------------------
1 | (source gnu)
2 | (source melpa)
3 |
4 | (package-file "go-impl.el")
5 |
6 | (development
7 | (depends-on "go-mode")
8 | (depends-on "helm"))
9 |
--------------------------------------------------------------------------------
/Changes:
--------------------------------------------------------------------------------
1 | Revision history for go-impl.el
2 |
3 | Revision 0.14 2017/01/26 syohex
4 | - Support custom impl path
5 | - Implement receiver completion(#8)
6 |
7 | Revision 0.13 2016/11/23 syohex
8 | - Drop Emacs 24.1 and 24.2 support
9 |
10 | Revision 0.12 2016/06/26 syohex
11 | - Improve for helm-mode
12 |
13 | Revision 0.11 2016/05/23 syohex
14 | - Bump up version for MELPA stable
15 |
16 | Revision 0.01 2016/05/20 syohex
17 | - Initial Release
18 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY : test test-function
2 |
3 | EMACS ?= emacs
4 | CASK ?= cask
5 |
6 | LOADPATH = -L .
7 |
8 | ELPA_DIR = $(shell EMACS=$(EMACS) $(CASK) package-directory)
9 |
10 | test: elpa
11 | $(CASK) exec $(EMACS) -Q -batch $(LOADPATH) \
12 | -l test/test-go-impl.el \
13 | -f ert-run-tests-batch-and-exit
14 |
15 | elpa: $(ELPA_DIR)
16 | $(ELPA_DIR): Cask
17 | $(CASK) install
18 | touch $@
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # go-impl.el [![travis badge][travis-badge]][travis-link] [![melpa badge][melpa-badge]][melpa-link] [![melpa stable badge][melpa-stable-badge]][melpa-stable-link]
2 |
3 | [impl](https://github.com/josharian/impl) for Emacs
4 |
5 | ## ScreenCast
6 |
7 | 
8 |
9 |
10 | ## Requirements
11 |
12 | - [impl](https://github.com/josharian/impl)
13 | - [godoc](https://godoc.org/golang.org/x/tools/cmd/godoc)
14 |
15 | ```
16 | % go get -u github.com/josharian/impl
17 | % go get -u golang.org/x/tools/cmd/godoc
18 | ```
19 |
20 |
21 | ## Installation
22 |
23 | `go-impl` is available on [MELPA](https://melpa.org/) and [MELPA stable](https://stable.melpa.org/)
24 |
25 | You can install `go-impl` with the following command.
26 |
27 | M-x package-install [RET] go-impl [RET]
28 |
29 |
30 | ## Command
31 |
32 | #### `M-x go-impl` `(go-impl receiver interface)`
33 |
34 | Insert snippet by `impl receiver interface`.
35 |
36 |
37 | ## Customization
38 |
39 | #### `go-impl-command`
40 |
41 | Location of `impl` command.
42 |
43 | #### `go-impl-aliases-alist`
44 |
45 | Association list of aliases of interface names. If interface name is matched
46 | with alias, then `go-impl` replaces alias with real interface name. Example is as below.
47 |
48 | ```lisp
49 | (custom-set-variables
50 | '(go-impl-aliases-alist '(("hh" . "http.Handler")
51 | ("irw" . "io.ReadWriter"))))
52 | ```
53 |
54 |
55 | #### `go-impl-enter-function`
56 |
57 | If this value is non-nil, go-impl enters into first function after inserting stubs.
58 |
59 | [travis-badge]: https://travis-ci.org/syohex/emacs-go-impl.svg
60 | [travis-link]: https://travis-ci.org/syohex/emacs-go-impl
61 | [melpa-link]: https://melpa.org/#/go-impl
62 | [melpa-stable-link]: https://stable.melpa.org/#/go-impl
63 | [melpa-badge]: https://melpa.org/packages/go-impl-badge.svg
64 | [melpa-stable-badge]: https://stable.melpa.org/packages/go-impl-badge.svg
65 |
--------------------------------------------------------------------------------
/go-impl.el:
--------------------------------------------------------------------------------
1 | ;;; go-impl.el --- impl integration for go-mode -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2017 by Syohei YOSHIDA
4 |
5 | ;; Author: Syohei YOSHIDA
6 | ;; URL: https://github.com/syohex/emacs-go-impl
7 | ;; Version: 0.14
8 | ;; Package-Requires: ((emacs "24.3") (go-mode "1.3.0"))
9 |
10 | ;; This program is free software; you can redistribute it and/or modify
11 | ;; it under the terms of the GNU General Public License as published by
12 | ;; the Free Software Foundation, either version 3 of the License, or
13 | ;; (at your option) any later version.
14 |
15 | ;; This program is distributed in the hope that it will be useful,
16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | ;; GNU General Public License for more details.
19 |
20 | ;; You should have received a copy of the GNU General Public License
21 | ;; along with this program. If not, see .
22 |
23 | ;;; Commentary:
24 |
25 | ;; Insert method stubs for implementing an interface by impl.
26 |
27 | ;;; Code:
28 |
29 | (require 'go-mode)
30 | (require 'cl-lib)
31 |
32 | (defgroup go-impl nil
33 | "`impl' integration for go-mode."
34 | :group 'go)
35 |
36 | (defcustom go-impl-command (executable-find "impl")
37 | "Location of impl command."
38 | :type 'file)
39 |
40 | (defcustom go-impl-aliases-alist nil
41 | "List of aliases for interface names"
42 | :type '(alist :key-type (string :tag "Alias")
43 | :value-type (string :tag "Real interface name")))
44 |
45 | (defcustom go-impl-enter-function nil
46 | "Move point into the first inserted function."
47 | :type 'boolean)
48 |
49 | (defvar go-impl--interface-cache (make-hash-table :test #'equal))
50 | (defvar go-impl--receiver-cache nil)
51 | (defvar go-impl--receiver-history nil)
52 | (defvar go-impl--interface-history nil)
53 |
54 | (defun go-impl--real-package-name (package)
55 | (if (string-match "\\([^/-]+\\)\\'" package)
56 | (match-string-no-properties 1 package)
57 | package))
58 |
59 | (defun go-impl--collect-receiver-types-1 (buf)
60 | (with-current-buffer buf
61 | (save-excursion
62 | (goto-char (point-min))
63 | (let (types)
64 | (while (re-search-forward "^type\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)" nil t)
65 | (unless (string= (match-string-no-properties 2) "interface")
66 | (push (match-string-no-properties 1) types)))
67 | types))))
68 |
69 | (defun go-impl--collect-receiver-types ()
70 | (or go-impl--receiver-cache
71 | (cl-loop with opened-bufs = (buffer-list)
72 | for file in (directory-files default-directory nil "\\.go\\'")
73 | unless (string-match-p "_test.go\\'" file)
74 | append
75 | (let ((buf (find-file-noselect file)))
76 | (prog1 (go-impl--collect-receiver-types-1 buf)
77 | (unless (memq buf opened-bufs)
78 | (kill-buffer buf))))
79 | into types
80 | finally return (setq go-impl--receiver-cache types))))
81 |
82 | (defun go-impl--collect-interface (package)
83 | (with-temp-buffer
84 | (unless (zerop (process-file "go" nil t nil "doc" "-src" package))
85 | (error "Failed: 'go doc -src %s'" package))
86 | (goto-char (point-min))
87 | (cl-loop with re = "^type\\s-+\\(\\S-+\\)\\s-+interface"
88 | with real-package = (go-impl--real-package-name package)
89 | while (re-search-forward re nil t)
90 | collect (concat real-package "." (match-string-no-properties 1)) into interfaces
91 | finally return (progn
92 | (puthash package (cl-copy-list interfaces) go-impl--interface-cache)
93 | interfaces))))
94 |
95 | (defun go-impl--collect-interfaces (packages)
96 | (cl-loop for package in packages
97 | if (gethash package go-impl--interface-cache)
98 | append it
99 | else
100 | append (go-impl--collect-interface package)))
101 |
102 | (defun go-impl--matched-packages (packages pattern)
103 | (cl-loop with regexp = (concat pattern "\\'")
104 | for p in packages
105 | when (string-match-p regexp p)
106 | collect p))
107 |
108 | (defun go-impl--completing-function (packages input predicate code)
109 | (let (candidates)
110 | (if (not (string-match "\\." input))
111 | (setq candidates
112 | (delete-dups
113 | (cl-loop with re = (concat "\\`" input)
114 | for package in (mapcar #'go-impl--real-package-name packages)
115 | when (string-match-p re package)
116 | collect package)))
117 | (let* ((interface-part (substring input 0 (match-beginning 0)))
118 | (matched (go-impl--matched-packages packages interface-part)))
119 | (setq candidates (go-impl--collect-interfaces matched))))
120 | (if (not code)
121 | (try-completion input candidates predicate)
122 | (all-completions input candidates predicate))))
123 |
124 | (defun go-impl--execute (receiver interface)
125 | (with-temp-buffer
126 | (unless (zerop (process-file go-impl-command nil t nil receiver interface))
127 | (error "Failed: impl '%s' %s" receiver interface))
128 | (buffer-string)))
129 |
130 | (defun go-impl--receiver-complete ()
131 | (interactive)
132 | (let ((input (minibuffer-contents)))
133 | (when (string-match "\\`\\S-+\\s-+\\*?\\(\\S-*\\)" input)
134 | (let* ((start-pos (+ (minibuffer-prompt-end) (match-beginning 1)))
135 | (receiver (match-string-no-properties 1 input))
136 | (candidates (go-impl--collect-receiver-types))
137 | (matches (all-completions receiver candidates)))
138 | (completion-in-region start-pos (point-max) matches)))))
139 |
140 | (defvar go-impl--local-command-map
141 | (let ((map (make-sparse-keymap)))
142 | (set-keymap-parent map minibuffer-local-map)
143 | (define-key map "\t" #'go-impl--receiver-complete)
144 | map))
145 |
146 | ;;;###autoload
147 | (defun go-impl (receiver interface)
148 | (interactive
149 | (let* ((packages (go-packages))
150 | (comp-fn (lambda (input predicate code)
151 | (when (bound-and-true-p helm-mode)
152 | (setq input (or (bound-and-true-p helm-input) input)))
153 | (go-impl--completing-function packages input predicate code))))
154 | (setq go-impl--receiver-cache nil)
155 | (list
156 | (read-from-minibuffer "Receiver: " nil go-impl--local-command-map nil
157 | 'go-impl--receiver-history nil t)
158 | (completing-read "Interface: " comp-fn nil nil nil 'go-impl--interface-history))))
159 | (when go-impl-aliases-alist
160 | (setq interface (or (assoc-default interface go-impl-aliases-alist)
161 | interface)))
162 | (let ((stubs (go-impl--execute receiver interface)))
163 | (save-excursion
164 | (insert stubs))
165 | (when go-impl-enter-function
166 | (forward-line)
167 | (back-to-indentation))))
168 |
169 | (provide 'go-impl)
170 |
171 | ;;; go-impl.el ends here
172 |
--------------------------------------------------------------------------------
/image/go-impl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacsorphanage/go-impl/1eebba6ccd02d11a5a82ad4540a8d562797bc3b3/image/go-impl.gif
--------------------------------------------------------------------------------
/test/test-go-impl.el:
--------------------------------------------------------------------------------
1 | ;;; test-go-impl.el --- Test for go-impl
2 |
3 | ;; Copyright (C) 2017 by Syohei YOSHIDA
4 |
5 | ;; Author: Syohei YOSHIDA
6 |
7 | ;; This program is free software; you can redistribute it and/or modify
8 | ;; it under the terms of the GNU General Public License as published by
9 | ;; the Free Software Foundation, either version 3 of the License, or
10 | ;; (at your option) any later version.
11 |
12 | ;; This program is distributed in the hope that it will be useful,
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | ;; GNU General Public License for more details.
16 |
17 | ;; You should have received a copy of the GNU General Public License
18 | ;; along with this program. If not, see .
19 |
20 | ;;; Code:
21 |
22 | (require 'ert)
23 | (require 'go-impl)
24 |
25 | (ert-deftest completing-function ()
26 | "go-impl--completing-function"
27 | (let ((got (go-impl--completing-function (go-packages) "i" nil t)))
28 | (should (member "io" got))
29 | (should (member "ioutil" got))))
30 |
31 | (ert-deftest matched-packages ()
32 | "go-impl--matched-packages"
33 | (let ((got (go-impl--matched-packages (go-packages) "json")))
34 | (should got)
35 | (should (member "encoding/json" got))))
36 |
37 | (ert-deftest collect-interface ()
38 | "go-impl--collect-interface"
39 | (let ((got (go-impl--collect-interface "encoding/json")))
40 | (should (member "json.Unmarshaler" got))
41 | (should (member "json.Marshaler" got))))
42 |
43 | (ert-deftest real-package-name ()
44 | "go-impl--real-package-name"
45 | (should (string= (go-impl--real-package-name "cmd/internal/goobj") "goobj"))
46 | (should (string= (go-impl--real-package-name "go-colortext") "colortext")))
47 |
48 | ;;; test-go-impl.el ends here
49 |
--------------------------------------------------------------------------------