├── .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 | ![Screencast of go-impl.el](image/go-impl.gif) 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 | --------------------------------------------------------------------------------