├── .gitignore ├── image ├── go-eldoc1.png ├── go-eldoc2.png └── go-eldoc3.png ├── Cask ├── .travis.yml ├── Makefile ├── test ├── test-helper.el ├── not-function.el ├── lhs.el └── function.el ├── README.md ├── Changes └── go-eldoc.el /.gitignore: -------------------------------------------------------------------------------- 1 | /.cask/ 2 | *.elc 3 | -------------------------------------------------------------------------------- /image/go-eldoc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emacsorphanage/go-eldoc/HEAD/image/go-eldoc1.png -------------------------------------------------------------------------------- /image/go-eldoc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emacsorphanage/go-eldoc/HEAD/image/go-eldoc2.png -------------------------------------------------------------------------------- /image/go-eldoc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emacsorphanage/go-eldoc/HEAD/image/go-eldoc3.png -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source gnu) 2 | (source melpa) 3 | 4 | (package-file "go-eldoc.el") 5 | 6 | (development 7 | (depends-on "ert")) 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - "1.8" 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 github.com/nsf/gocode 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 | matrix: 17 | allow_failures: 18 | - go: "tip" 19 | script: 20 | - go version 21 | - make test 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UNAME_S=$(shell uname -s) 2 | ifeq ($(UNAME_S),Darwin) 3 | EMACS ?= /Applications/Emacs.app/Contents/MacOS/Emacs 4 | else 5 | EMACS ?= emacs 6 | endif 7 | 8 | EMACS ?= emacs 9 | CASK ?= cask 10 | 11 | LOADPATH = -L . 12 | LOAD_HELPER = -l test/test-helper.el 13 | 14 | ELPA_DIR = $(shell EMACS=$(EMACS) $(CASK) package-directory) 15 | 16 | test: elpa 17 | $(CASK) exec $(EMACS) -Q -batch $(LOADPATH) $(LOAD_HELPER) \ 18 | -l test/function.el -l test/not-function.el \ 19 | -l test/lhs.el \ 20 | -f ert-run-tests-batch-and-exit 21 | 22 | test-function: 23 | $(CASK) exec $(EMACS) -Q -batch $(LOADPATH) $(LOAD_HELPER) \ 24 | -l test/function.el \ 25 | -f ert-run-tests-batch-and-exit 26 | 27 | test-not-function: 28 | $(CASK) exec $(EMACS) -Q -batch $(LOADPATH) $(LOAD_HELPER) \ 29 | -l test/not-function.el \ 30 | -f ert-run-tests-batch-and-exit 31 | 32 | test-lhs: 33 | $(CASK) exec $(EMACS) -Q -batch $(LOADPATH) $(LOAD_HELPER) \ 34 | -l test/lhs.el \ 35 | -f ert-run-tests-batch-and-exit 36 | 37 | elpa: $(ELPA_DIR) 38 | $(ELPA_DIR): Cask 39 | $(CASK) install 40 | touch $@ 41 | -------------------------------------------------------------------------------- /test/test-helper.el: -------------------------------------------------------------------------------- 1 | ;;; test-helper.el --- helper for testing go-eldoc 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 | ;;; Commentary: 21 | 22 | ;;; Code: 23 | 24 | (require 'go-eldoc) 25 | 26 | (defmacro with-go-temp-buffer (code &rest body) 27 | "Insert `code' and enable `go-mode'. cursor is beginning of buffer" 28 | (declare (indent 0) (debug t)) 29 | `(with-temp-buffer 30 | (insert ,code) 31 | (goto-char (point-min)) 32 | (go-mode) 33 | (font-lock-fontify-buffer) 34 | ,@body)) 35 | 36 | (cl-defun forward-cursor-on (pattern &optional (count 1)) 37 | (let ((case-fold-search nil)) 38 | (re-search-forward pattern nil nil count) 39 | (goto-char (match-beginning 0)))) 40 | 41 | (cl-defun backward-cursor-on (pattern &optional (count 1)) 42 | (let ((case-fold-search nil)) 43 | (re-search-backward pattern nil nil count) 44 | (goto-char (match-beginning 0)))) 45 | 46 | (defun face-at-cursor-p (face) 47 | (eq (face-at-point) face)) 48 | 49 | ;;; test-helper.el ends here 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-eldoc.el [![travis badge][travis-badge]][travis-link] [![melpa badge][melpa-badge]][melpa-link] [![melpa stable badge][melpa-stable-badge]][melpa-stable-link] 2 | 3 | ## Introduction 4 | 5 | `go-eldoc.el` provides eldoc for Go language. `go-eldoc.el` shows type information 6 | for variable, functions and current argument position of function. 7 | 8 | 9 | ## Screenshot 10 | 11 | ### Argument Type of Function 12 | 13 | ![Screenshot of showing argument type of function](image/go-eldoc1.png) 14 | 15 | ### Variable Type Information 16 | 17 | ![Screenshot of showing variable type information](image/go-eldoc2.png) 18 | 19 | ### Return Value Type 20 | 21 | ![Screenshot of showing return value type](image/go-eldoc3.png) 22 | 23 | 24 | ## Dependency 25 | 26 | * [gocode](https://github.com/nsf/gocode) 27 | * [go-mode](https://github.com/dominikh/go-mode.el) 28 | 29 | You can install `go-mode` with package.el from [MELPA](https://melpa.org/). 30 | And you can install `gocode` by `go get` as below. 31 | 32 | ``` 33 | % go get -u github.com/nsf/gocode 34 | ``` 35 | 36 | 37 | ## Installation 38 | 39 | You can install `go-eldoc.el` from [MELPA](https://melpa.org/) with package.el. 40 | 41 | ```lisp 42 | (require 'package) 43 | (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) 44 | (package-initialize) 45 | (package-refresh-contents) 46 | ``` 47 | 48 | evaluate this code and M-x package-install go-eldoc. 49 | 50 | 51 | ## Setup 52 | Call `go-eldoc-setup` function at `go-mode-hook` 53 | 54 | ```lisp 55 | (require 'go-eldoc) ;; Don't need to require, if you install by package.el 56 | (add-hook 'go-mode-hook 'go-eldoc-setup) 57 | ``` 58 | 59 | ## Customize 60 | You can change face of current argument position by `eldoc-highlight-function-argument` 61 | like this. 62 | 63 | ```lisp 64 | (set-face-attribute 'eldoc-highlight-function-argument nil 65 | :underline t :foreground "green" 66 | :weight 'bold) 67 | ``` 68 | 69 | ##### `go-eldoc-gocode`(Default: `gocode`) 70 | 71 | `gocode` location. You need not to set this variable if you set (`$GOPATH/bin`) to PATH environment variable correctly. 72 | 73 | ##### `go-eldoc-gocode-args`(Default: `nil`) 74 | 75 | Arguments of `gocode` command. Type of this variable is list of strings. 76 | 77 | [travis-badge]: https://travis-ci.org/syohex/emacs-go-eldoc.svg 78 | [travis-link]: https://travis-ci.org/syohex/emacs-go-eldoc 79 | [melpa-link]: https://melpa.org/#/go-eldoc 80 | [melpa-stable-link]: https://stable.melpa.org/#/go-eldoc 81 | [melpa-badge]: https://melpa.org/packages/go-eldoc-badge.svg 82 | [melpa-stable-badge]: https://stable.melpa.org/packages/go-eldoc-badge.svg 83 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | Revision history for go-eldoc.el 2 | 3 | Version 0.30 2017/02/12 syohex 4 | - Drop older Emacs support for maintenance 5 | 6 | Version 0.28 2016/10/12 syohex 7 | - Add customize variable of gocode argument(Thanks Konstantin Shaposhnikov) 8 | 9 | Version 0.27 2016/03/07 syohex 10 | - Refactoring code 11 | - Update docstrings 12 | 13 | Version 0.26 2015/08/22 syohex 14 | - Fix error case that funcall in brackets(#39) 15 | 16 | Version 0.25 2015/06/10 syohex 17 | - Fix showing wrong function information if assignment operator in comment(#33) 18 | 19 | Version 0.24 2015/06/06 syohex 20 | - Fix case insensitive match issue(#32) 21 | 22 | Version 0.23 2015/03/31 syohex 23 | - Fix incorrect highlight issue(#29) 24 | go-eldoc.el highlighted incorrectly on left hand side, where function returns 25 | function type which has no name. 26 | 27 | Version 0.22 2015/02/23 syohex 28 | - Update minimum go-mode version 29 | 30 | Version 0.21 2014/12/19 syohex 31 | - Fix error when highlights return value of function 32 | which has map type arguments(#26) 33 | 34 | Version 0.20 2014/12/02 syohex 35 | - Fix highlighting function parameter issue 36 | - Fix byte-compile issue 37 | 38 | Version 0.19 2014/09/22 syohex 39 | - Fix regression issue(Thanks fbergroth) 40 | - Remove needless code 41 | 42 | Version 0.18 2014/09/19 syohex 43 | - Refactoring code 44 | 45 | Version 0.17 2014/06/09 syohex 46 | - Fix invalid highlighting case 47 | 48 | Version 0.16 2014/05/30 syohex 49 | - Improve highlighting in left hand side expression 50 | - Improve displaying 'make' signature 51 | 52 | Version 0.15 2014/05/09 syohex 53 | - Show type information for variable, package, method etc 54 | 55 | Version 0.14 2014/03/08 syohex 56 | - Enable lexical-binding 57 | 58 | Version 0.13 2014/02/21 syohex 59 | - Switch to cl-lib 60 | - Fix byte compile warning 61 | 62 | Version 0.12 2013/12/16 syohex 63 | - Fix type only argument case(#10) 64 | Reported by Bad-ptr 65 | 66 | Version 0.11 2013/12/15 syohex 67 | - Fix invalid argument analyze(#8) 68 | Reported by Bad-ptr 69 | 70 | Version 0.10 2013/10/29 syohex 71 | - Remove go-autocomplete dependency 72 | Thanks dominikh 73 | 74 | Version 0.09 2013/10/16 syohex 75 | - Fix case of channel slice 76 | 77 | Version 0.08 2013/10/15 syohex 78 | - Fix case of channel type display 79 | 80 | Version 0.07 2013/08/13 syohex 81 | - Fix case of `fmt.Fprint(os.Stdout, ",})", ` 82 | 83 | Version 0.06 2013/08/06 syohex 84 | - Support builtin functions('append', 'copy' etc) 85 | 86 | Version 0.05 2013/07/12 syohex 87 | - Improve calculating current index of arguments(Thanks dominikh) 88 | 89 | Version 0.04 2013/07/11 syohex 90 | - Fix case that function type has return types 91 | - Improve for anonymous function 92 | - Improve for highlighting current argument index 93 | 94 | Version 0.03 2013/07/08 syohex 95 | - Fix case that return type is slice 96 | 97 | Version 0.02 2013/07/07 syohex 98 | - Fix bug for not saving old-point(dominikh) 99 | - improve regular expression searching(dominikh) 100 | 101 | Version 0.01 2013/07/06 syohex 102 | - init version 103 | -------------------------------------------------------------------------------- /test/not-function.el: -------------------------------------------------------------------------------- 1 | ;;; not-function.el --- Test for not function type, variable, package, etc 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 | ;;; Commentary: 21 | 22 | ;;; Code: 23 | 24 | (require 'cl-lib) 25 | 26 | (require 'ert) 27 | (require 'go-eldoc) 28 | 29 | ;; 30 | ;; Variable name 31 | ;; 32 | 33 | (ert-deftest local-variable () 34 | "Show local variable type" 35 | (with-go-temp-buffer 36 | " 37 | package main 38 | func foo() { 39 | var v string = \"hello\" 40 | a := v + \" world\" 41 | } 42 | " 43 | (forward-cursor-on "\\bv\\b" 2) 44 | (let ((got (go-eldoc--documentation-function)) 45 | (expected "v: string")) 46 | (should (string= got expected))))) 47 | 48 | (ert-deftest local-variable-has-long-name () 49 | "Show local variable type which has long name more than 1 chracter" 50 | (with-go-temp-buffer 51 | " 52 | package main 53 | 54 | func foo() { 55 | var this_is_variable float32 = 3.14 56 | a := this_is_variable + 1.0 57 | fmt.Println(this_is_variable) 58 | } 59 | " 60 | (forward-cursor-on "this_is_variable" 2) 61 | (let ((got (go-eldoc--documentation-function)) 62 | (expected "this_is_variable: float32")) 63 | (should (string= got expected))))) 64 | 65 | (ert-deftest argument-variable () 66 | "Show argument variable" 67 | (with-go-temp-buffer 68 | " 69 | package main 70 | func foo(arg []byte) { 71 | arg = []byte{'a', 'b', 'c'} 72 | } 73 | " 74 | (forward-cursor-on "arg = ") 75 | (let ((got (go-eldoc--documentation-function)) 76 | (expected "arg: []byte")) 77 | (should (string= got expected))))) 78 | 79 | (ert-deftest global-variable () 80 | "Show global variable with typed declaration" 81 | (with-go-temp-buffer 82 | " 83 | package main 84 | var global string = \"GlobalVariable\" 85 | func foo() { 86 | v := global 87 | } 88 | " 89 | (goto-char (point-max)) 90 | (backward-cursor-on "global") 91 | (let ((got (go-eldoc--documentation-function)) 92 | (expected "global: string")) 93 | (should (string= got expected))))) 94 | 95 | (ert-deftest function-type () 96 | "Show function type variable" 97 | (with-go-temp-buffer 98 | " 99 | package main 100 | func foo(a int, b int) int { 101 | return a + b 102 | } 103 | func main() { 104 | funcvar := foo 105 | c := funcvar(1, 2) 106 | } 107 | " 108 | (forward-cursor-on "funcvar(") 109 | (let ((got (go-eldoc--documentation-function)) 110 | (expected "funcvar: func(a int, b int) int")) 111 | (should (string= got expected))))) 112 | 113 | (ert-deftest array-index () 114 | "Show array index variable" 115 | (with-go-temp-buffer 116 | " 117 | package main 118 | func main() { 119 | var foo int = 2 120 | bar := []int{0, 1, 2} 121 | bar[foo] 122 | } 123 | " 124 | (forward-cursor-on "foo\\]") 125 | (let ((got (go-eldoc--documentation-function)) 126 | (expected "foo: int")) 127 | (should (string= got expected))))) 128 | 129 | (ert-deftest array-element-property () 130 | "Show array elemet property" 131 | (with-go-temp-buffer 132 | " 133 | package main 134 | 135 | type Foo struct { bar int } 136 | 137 | func main() { 138 | var foo [10]Foo 139 | foo[9].bar 140 | } 141 | " 142 | (forward-cursor-on "\\.bar") 143 | (forward-char) 144 | (let ((got (go-eldoc--documentation-function)) 145 | (expected "foo[9].bar: int")) 146 | (should (string= got expected))))) 147 | 148 | ;; 149 | ;; Method 150 | ;; 151 | 152 | (ert-deftest method-type () 153 | "Show global variable with typed declaration" 154 | (with-go-temp-buffer 155 | " 156 | package main 157 | 158 | type Foo struct { 159 | } 160 | 161 | func (f *Foo) bar(a int) int { 162 | return a + 10 163 | } 164 | 165 | func main() { 166 | foo := Foo{} 167 | foo.bar() 168 | } 169 | " 170 | (forward-cursor-on "bar()") 171 | (let ((got (go-eldoc--documentation-function)) 172 | (expected "foo.bar: func(a int) int")) 173 | (should (string= got expected))))) 174 | 175 | ;; 176 | ;; package name 177 | ;; 178 | 179 | (ert-deftest package-name () 180 | "Show package name" 181 | (with-go-temp-buffer 182 | " 183 | package main 184 | 185 | import \"fmt\" 186 | 187 | func foo() { 188 | fmt.Println() 189 | } 190 | " 191 | (forward-cursor-on "fmt\\.") 192 | (let ((got (go-eldoc--documentation-function)) 193 | (expected "fmt: package")) 194 | (should (string= got expected))))) 195 | 196 | (ert-deftest case-sensitive-match-type () 197 | "Match only case sensitive" 198 | (with-go-temp-buffer 199 | " 200 | package main 201 | 202 | import \"os\" 203 | 204 | func main() { 205 | os.MkDIR( ) 206 | os.Mkdir( ) 207 | } 208 | " 209 | (forward-cursor-on "MkDIR") 210 | (should-not (go-eldoc--documentation-function)) 211 | 212 | (forward-cursor-on "Mkdir") 213 | (should (go-eldoc--documentation-function)))) 214 | 215 | ;;; not-function.el end here 216 | -------------------------------------------------------------------------------- /test/lhs.el: -------------------------------------------------------------------------------- 1 | ;;; lhs.el --- Test for left hand side highlighting 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 | ;;; Commentary: 21 | 22 | ;;; Code: 23 | 24 | (require 'cl-lib) 25 | 26 | (require 'ert) 27 | (require 'go-eldoc) 28 | 29 | ;; 30 | ;; Tests for left hand side 31 | ;; 32 | 33 | (ert-deftest one-return-value () 34 | "Function has one return value" 35 | (with-go-temp-buffer 36 | " 37 | package main 38 | func foo(arg int) error { 39 | } 40 | 41 | func main () { 42 | err := foo(10) 43 | } 44 | " 45 | (goto-char (point-max)) 46 | (backward-cursor-on "err") 47 | (let ((got (go-eldoc--documentation-function)) 48 | (expected "foo: (arg int) error")) 49 | (should (string= got expected)) 50 | 51 | (let ((highlighted-part (substring got -5))) 52 | (should (eq (get-text-property 0 'face highlighted-part) 53 | 'eldoc-highlight-function-argument)))))) 54 | 55 | (ert-deftest one-return-value-with-name () 56 | "Function has one named return value" 57 | (with-go-temp-buffer 58 | " 59 | package main 60 | func foo(arg int) (ret error) { 61 | } 62 | 63 | func main () { 64 | err := foo(10) 65 | } 66 | " 67 | (goto-char (point-max)) 68 | (backward-cursor-on "err") 69 | (let ((got (go-eldoc--documentation-function)) 70 | (expected "foo: (arg int) (ret error)")) 71 | (should (string= got expected))))) 72 | 73 | (ert-deftest multiple-return-values () 74 | "Function has multile return values" 75 | (with-go-temp-buffer 76 | " 77 | package main 78 | func foo(arg int) (int, double, error) { 79 | } 80 | 81 | func main () { 82 | bar, baz, err := foo(10) 83 | } 84 | " 85 | (goto-char (point-max)) 86 | (backward-cursor-on "bar") 87 | (let ((got (go-eldoc--documentation-function)) 88 | (expected "foo: (arg int) (int, double, error)")) 89 | (should (string= got expected)) 90 | (should (eq (get-text-property 0 'face (substring got -19 -16)) 91 | 'eldoc-highlight-function-argument)) 92 | (should-not (get-text-property 0 'face (substring got -14 -8))) 93 | 94 | (forward-cursor-on "baz") 95 | (let ((got (go-eldoc--documentation-function))) 96 | (should (string= got expected)) 97 | (should (eq (get-text-property 0 'face (substring got -14 -9)) 98 | 'eldoc-highlight-function-argument)) 99 | (should-not (get-text-property 0 'face (substring got -19 -16)))) 100 | 101 | (forward-cursor-on "err") 102 | (let ((got (go-eldoc--documentation-function))) 103 | (should (string= got expected)) 104 | (should (eq (get-text-property 0 'face (substring got -6 -2)) 105 | 'eldoc-highlight-function-argument)) 106 | (should-not (get-text-property 0 'face (substring got -19 -16))) 107 | (should-not (get-text-property 0 'face (substring got -14 -9))))))) 108 | 109 | (ert-deftest separated-by-semicolon () 110 | "assignment expression with semicolon" 111 | (with-go-temp-buffer 112 | " 113 | package main 114 | func foo(arg int) error { 115 | } 116 | 117 | func main () { 118 | if err := foo(10); err != nil { 119 | } 120 | } 121 | " 122 | (goto-char (point-max)) 123 | (backward-cursor-on "if") 124 | (forward-cursor-on "err") 125 | (let ((got (go-eldoc--documentation-function)) 126 | (expected "foo: (arg int) error")) 127 | (should (string= got expected)) 128 | 129 | (let ((highlighted-part (substring got -5))) 130 | (should (eq (get-text-property 0 'face highlighted-part) 131 | 'eldoc-highlight-function-argument)))) 132 | 133 | (forward-cursor-on "10") 134 | (let* ((got (go-eldoc--documentation-function)) 135 | (highlighted-part (substring got 6 13))) 136 | (should (eq (get-text-property 0 'face highlighted-part) 137 | 'eldoc-highlight-function-argument))))) 138 | 139 | (ert-deftest return-function-type-with-no-name () 140 | "function returns function type which has no name" 141 | (with-go-temp-buffer 142 | " 143 | package main 144 | 145 | import \"net/http\" 146 | import \"error\" 147 | 148 | func FollowRedirectsCallback(howmany int) func(r *http.Request, via []*http.Request) error { 149 | } 150 | 151 | func main() { 152 | fun := FollowRedirectsCallback(10) 153 | } 154 | " 155 | (forward-cursor-on "main" 2) 156 | (forward-cursor-on "fun") 157 | (let ((got (go-eldoc--documentation-function))) 158 | (should (eq (get-text-property 0 'face (substring got -20)) 159 | 'eldoc-highlight-function-argument)) 160 | 161 | (should (eq (get-text-property 0 'face (substring got -10)) 162 | 'eldoc-highlight-function-argument)) 163 | 164 | (should (eq (get-text-property 0 'face (substring got -5)) 165 | 'eldoc-highlight-function-argument))))) 166 | 167 | (ert-deftest dont-show-next-statement () 168 | "go-eldoc must not show another statement information." 169 | (with-go-temp-buffer 170 | " 171 | package main 172 | 173 | import \"fmt\" 174 | 175 | func Foo(a int) { 176 | fmt.Println(a) 177 | } 178 | 179 | type Bar struct { 180 | aaa int 181 | } 182 | 183 | func main() { 184 | bb := Bar{cc: 10} 185 | aa := bb.cc 186 | Foo(aa) 187 | } 188 | " 189 | (forward-cursor-on "main" 2) 190 | (forward-cursor-on "aa") 191 | (let ((got (go-eldoc--documentation-function))) 192 | (should-not got)))) 193 | 194 | (ert-deftest regression-test-26 () 195 | "Regression test of #26. Show eldoc of left hand side variable 196 | without any exceptions." 197 | (with-go-temp-buffer 198 | " 199 | package main 200 | 201 | type Profile map[string]string 202 | type Requires Profile 203 | 204 | func Get(name string, requires Requires) (*Profile, error) { 205 | } 206 | 207 | func main () { 208 | res, err := Get(\"foo\", Requires{ 209 | }) 210 | } 211 | " 212 | (goto-char (point-min)) 213 | (forward-cursor-on "\\bres\\b") 214 | (should (go-eldoc--documentation-function)))) 215 | 216 | (ert-deftest assign-operator-in-comment-or-string () 217 | "Ignore assignment operator in comment or string" 218 | (with-go-temp-buffer 219 | " 220 | package main 221 | 222 | import \"math/big\" 223 | 224 | func main() { 225 | a := big.NewInt() 226 | var base int64 = 2 227 | exponent := 1 228 | 229 | a.Exp(base, big.NewInt(int64(exponent)), nil) //16^1 = 16 230 | } 231 | " 232 | (forward-cursor-on "base,") 233 | (let ((got (go-eldoc--documentation-function))) 234 | (should (string-match-p "Exp" got))))) 235 | 236 | (ert-deftest method-chanining () 237 | "Method chaining" 238 | (with-go-temp-buffer 239 | " 240 | package main 241 | 242 | type Foo struct { 243 | } 244 | 245 | func (f *Foo) f1() *Foo { 246 | return f 247 | } 248 | 249 | func (f *Foo) f2(a int) (*Foo, int) { 250 | return f, 10+a 251 | } 252 | 253 | func f3() int { 254 | return 3 255 | } 256 | 257 | func main() { 258 | f := &Foo{} 259 | a, b := f.f1().f2(f3()) 260 | } 261 | " 262 | (forward-cursor-on "a,") 263 | (let ((got (go-eldoc--documentation-function))) 264 | (should (string= "f2: (a int) (*Foo, int)" got))))) 265 | 266 | (ert-deftest funcall-in-backets () 267 | "funcall in brackets" 268 | (with-go-temp-buffer 269 | " 270 | package main 271 | 272 | func f1() int { 273 | return 3 274 | } 275 | 276 | func main() { 277 | var a[10] 278 | b := a[f1()] 279 | } 280 | " 281 | (forward-cursor-on "b") 282 | ;; should not error 283 | (should (progn (go-eldoc--documentation-function) t)))) 284 | 285 | ;;; lhs.el end here 286 | -------------------------------------------------------------------------------- /test/function.el: -------------------------------------------------------------------------------- 1 | ;;; function.el --- Test for function signature of go-mode.el 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 | ;;; Commentary: 21 | 22 | ;;; Code: 23 | 24 | (require 'cl-lib) 25 | 26 | (require 'ert) 27 | (require 'go-eldoc) 28 | 29 | ;; 30 | ;; Tests for Signature String 31 | ;; 32 | 33 | (ert-deftest one-argument-no-retval () 34 | "Function has one argument and no return value" 35 | (with-go-temp-buffer 36 | " 37 | package main 38 | func foo(arg int) { 39 | } 40 | 41 | func main() { 42 | foo( ) 43 | } 44 | " 45 | (forward-cursor-on "( )") 46 | (forward-char 1) 47 | (let ((got (go-eldoc--documentation-function)) 48 | (expected "foo: (arg int) ")) 49 | (should (string= got expected))))) 50 | 51 | (ert-deftest one-argument-one-retval () 52 | "Function has one argument and one return value" 53 | (with-go-temp-buffer 54 | " 55 | package main 56 | func foo(arg int) int { 57 | } 58 | 59 | func main() { 60 | foo( ) 61 | } 62 | " 63 | (forward-cursor-on "( )") 64 | (forward-char 1) 65 | (let ((got (go-eldoc--documentation-function)) 66 | (expected "foo: (arg int) int")) 67 | (should (string= got expected))))) 68 | 69 | (ert-deftest one-argument-one-retval-has-name () 70 | "Function has one argument and one return value has name" 71 | (with-go-temp-buffer 72 | " 73 | package main 74 | func foo(arg int) (ret int) { 75 | } 76 | 77 | func main() { 78 | foo( ) 79 | } 80 | " 81 | (forward-cursor-on "( )") 82 | (forward-char 1) 83 | (let ((got (go-eldoc--documentation-function)) 84 | (expected "foo: (arg int) (ret int)")) 85 | (should (string= got expected))))) 86 | 87 | (ert-deftest one-argument-contains-underscore () 88 | "Function has one argument contains underscore(#8)" 89 | (with-go-temp-buffer 90 | " 91 | package main 92 | func foo(arg_name int) (ret int) { 93 | } 94 | 95 | func main() { 96 | foo( ) 97 | } 98 | " 99 | (forward-cursor-on "( )") 100 | (forward-char 1) 101 | (let ((got (go-eldoc--documentation-function)) 102 | (expected "foo: (arg_name int) (ret int)")) 103 | (should (string= got expected))))) 104 | 105 | (ert-deftest one-argument-multiple-retvals () 106 | "Function has one argument and multiple return values" 107 | (with-go-temp-buffer 108 | " 109 | package main 110 | func foo(arg int) (int, int) { 111 | } 112 | 113 | func main() { 114 | foo( ) 115 | } 116 | " 117 | (forward-cursor-on "( )") 118 | (forward-char 1) 119 | (let ((got (go-eldoc--documentation-function)) 120 | (expected "foo: (arg int) (int, int)")) 121 | (should (string= got expected))))) 122 | 123 | (ert-deftest multiple-arguments-one-retval () 124 | "Function has multiple arguments and one return value" 125 | (with-go-temp-buffer 126 | " 127 | package main 128 | func foo(arg1 int, arg2 int) int { 129 | } 130 | 131 | func main() { 132 | foo( ) 133 | } 134 | " 135 | (forward-cursor-on "( )") 136 | (forward-char 1) 137 | (let ((got (go-eldoc--documentation-function)) 138 | (expected "foo: (arg1 int, arg2 int) int")) 139 | (should (string= got expected))))) 140 | 141 | (ert-deftest multiple-arguments-multiple-retval () 142 | "Function has multiple arguments and multiple return values" 143 | (with-go-temp-buffer 144 | " 145 | package main 146 | func foo(arg1 int, arg2 string) (int, string) { 147 | } 148 | 149 | func main() { 150 | foo( ) 151 | } 152 | " 153 | (forward-cursor-on "( )") 154 | (forward-char 1) 155 | (let ((got (go-eldoc--documentation-function)) 156 | (expected "foo: (arg1 int, arg2 string) (int, string)")) 157 | (should (string= got expected))))) 158 | 159 | (ert-deftest multiple-arguments-multiple-retval-have-names () 160 | "Function has multiple arguments and multiple return values have names" 161 | (with-go-temp-buffer 162 | " 163 | package main 164 | func foo(arg1 int, arg2 string) (ret1 int, ret2 string) { 165 | } 166 | 167 | func main() { 168 | foo( ) 169 | } 170 | " 171 | (forward-cursor-on "( )") 172 | (forward-char 1) 173 | (let ((got (go-eldoc--documentation-function)) 174 | (expected "foo: (arg1 int, arg2 string) (ret1 int, ret2 string)")) 175 | (should (string= got expected))))) 176 | 177 | (ert-deftest multiple-arguments-omit-type () 178 | "Function has multiple argumes and multple return values but type is omitted" 179 | (with-go-temp-buffer 180 | " 181 | package main 182 | func foo(arg1, arg2 string) (ret1, ret2 int) { 183 | } 184 | 185 | func main() { 186 | foo( ) 187 | } 188 | " 189 | (forward-cursor-on "( )") 190 | (forward-char 1) 191 | (let ((got (go-eldoc--documentation-function)) 192 | (expected "foo: (arg1, arg2 string) (ret1, ret2 int)")) 193 | (should (string= got expected))))) 194 | 195 | (ert-deftest arguments-in-multiple-lines () 196 | "Arguments in multiple lines" 197 | (with-go-temp-buffer 198 | " 199 | package main 200 | func foo( 201 | arg1 int, 202 | arg2 bool, 203 | arg3 string 204 | ) float { 205 | } 206 | 207 | func main() { 208 | foo( ) 209 | } 210 | " 211 | (forward-cursor-on "( )") 212 | (forward-char 1) 213 | (let ((got (go-eldoc--documentation-function)) 214 | (expected "foo: (arg1 int, arg2 bool, arg3 string) float")) 215 | (should (string= got expected))))) 216 | 217 | (ert-deftest channel-argument () 218 | "Function has channel argument" 219 | (with-go-temp-buffer 220 | " 221 | package main 222 | func foo(ch <-chan string) int { 223 | } 224 | 225 | func main() { 226 | foo( ) 227 | } 228 | " 229 | (forward-cursor-on "( )") 230 | (forward-char 1) 231 | (let ((got (go-eldoc--documentation-function)) 232 | (expected "foo: (ch <-chan string) int")) 233 | (should (string= got expected))))) 234 | 235 | (ert-deftest channel-argument-and-channel-retval () 236 | "Function has one argument and one return value" 237 | (with-go-temp-buffer 238 | " 239 | package main 240 | func foo(ch <-chan string) chan<- bool { 241 | } 242 | 243 | func main() { 244 | foo( ) 245 | } 246 | " 247 | (forward-cursor-on "( )") 248 | (forward-char 1) 249 | (let ((got (go-eldoc--documentation-function)) 250 | (expected "foo: (ch <-chan string) (chan<- bool)")) 251 | (should (string= got expected))))) 252 | 253 | (ert-deftest list-argument () 254 | "Function has list argument" 255 | (with-go-temp-buffer 256 | " 257 | package main 258 | func foo(arg []int) int { 259 | } 260 | 261 | func main() { 262 | foo( ) 263 | } 264 | " 265 | (forward-cursor-on "( )") 266 | (forward-char 1) 267 | (let ((got (go-eldoc--documentation-function)) 268 | (expected "foo: (arg []int) int")) 269 | (should (string= got expected))))) 270 | 271 | (ert-deftest list-return-value () 272 | "Function has channel argument" 273 | (with-go-temp-buffer 274 | " 275 | package main 276 | func foo(arg int) []int { 277 | } 278 | 279 | func main() { 280 | foo( ) 281 | } 282 | " 283 | (forward-cursor-on "( )") 284 | (forward-char 1) 285 | (let ((got (go-eldoc--documentation-function)) 286 | (expected "foo: (arg int) []int")) 287 | (should (string= got expected))))) 288 | 289 | (ert-deftest interface-argument () 290 | "Function has interface argument" 291 | (with-go-temp-buffer 292 | " 293 | package main 294 | func foo(arg interface{}) int { 295 | } 296 | 297 | func main() { 298 | foo( ) 299 | } 300 | " 301 | (forward-cursor-on "( )") 302 | (forward-char 1) 303 | (let ((got (go-eldoc--documentation-function)) 304 | (expected "foo: (arg interface{}) int")) 305 | (should (string= got expected))))) 306 | 307 | (ert-deftest interface-return-value () 308 | "Function has interface return value" 309 | (with-go-temp-buffer 310 | " 311 | package main 312 | func foo(arg int) interface{} { 313 | } 314 | 315 | func main() { 316 | foo( ) 317 | } 318 | " 319 | (forward-cursor-on "( )") 320 | (forward-char 1) 321 | (let ((got (go-eldoc--documentation-function)) 322 | (expected "foo: (arg int) interface{}")) 323 | (should (string= got expected))))) 324 | 325 | (ert-deftest interface-return-value () 326 | "Function has interface return value" 327 | (with-go-temp-buffer 328 | " 329 | package main 330 | func foo(arg int) interface{} { 331 | } 332 | 333 | func main() { 334 | foo( ) 335 | } 336 | " 337 | (forward-cursor-on "( )") 338 | (forward-char 1) 339 | (let ((got (go-eldoc--documentation-function)) 340 | (expected "foo: (arg int) interface{}")) 341 | (should (string= got expected))))) 342 | 343 | (ert-deftest list-of-channel-argument () 344 | "Function has list of channels argument" 345 | (with-go-temp-buffer 346 | " 347 | package main 348 | func foo(ch [2]string) int { 349 | } 350 | 351 | func main() { 352 | foo( ) 353 | } 354 | " 355 | (forward-cursor-on "( )") 356 | (forward-char 1) 357 | (let ((got (go-eldoc--documentation-function)) 358 | (expected "foo: (ch [2]string) int")) 359 | (should (string= got expected))))) 360 | 361 | (ert-deftest list-of-interface-argument () 362 | "Function has list of channels argument" 363 | (with-go-temp-buffer 364 | " 365 | package main 366 | func foo(arg [999]interface{}) int { 367 | } 368 | 369 | func main() { 370 | foo( ) 371 | } 372 | " 373 | (forward-cursor-on "( )") 374 | (forward-char 1) 375 | (let ((got (go-eldoc--documentation-function)) 376 | (expected "foo: (arg [999]interface{}) int")) 377 | (should (string= got expected))))) 378 | 379 | (ert-deftest slice-of-channel-argument () 380 | "Function has slice of channels argument" 381 | (with-go-temp-buffer 382 | " 383 | package main 384 | func foo(ch []string) int { 385 | } 386 | 387 | func main() { 388 | foo( ) 389 | } 390 | " 391 | (forward-cursor-on "( )") 392 | (forward-char 1) 393 | (let ((got (go-eldoc--documentation-function)) 394 | (expected "foo: (ch []string) int")) 395 | (should (string= got expected))))) 396 | 397 | (ert-deftest slice-of-interface-argument () 398 | "Function has slice of channels argument" 399 | (with-go-temp-buffer 400 | " 401 | package main 402 | func foo(arg []interface{}) int { 403 | } 404 | 405 | func main() { 406 | foo( ) 407 | } 408 | " 409 | (forward-cursor-on "( )") 410 | (forward-char 1) 411 | (let ((got (go-eldoc--documentation-function)) 412 | (expected "foo: (arg []interface{}) int")) 413 | (should (string= got expected))))) 414 | 415 | (ert-deftest type-only-argument () 416 | "Function has type only argument" 417 | (with-go-temp-buffer 418 | " 419 | package main 420 | import \"time\" 421 | type test_interface interface{ 422 | test_mf(arg time.Duration) 423 | } 424 | 425 | func main() { 426 | var ti test_interface 427 | ti.test_mf( ) 428 | } 429 | " 430 | (forward-cursor-on "main") 431 | (forward-cursor-on "main") 432 | (forward-cursor-on "( )") 433 | (forward-char 1) 434 | 435 | (let ((got (go-eldoc--documentation-function)) 436 | (expected "test_mf: (arg time.Duration) ")) 437 | (should (string= got expected))))) 438 | 439 | (ert-deftest type-only-argument-complex () 440 | "Function has type only argument which is complex(#10)" 441 | (with-go-temp-buffer 442 | " 443 | package main 444 | import \"time\" 445 | type test_interface interface{ 446 | test_ms([]time.Duration) 447 | } 448 | 449 | func main() { 450 | var ti test_interface 451 | ti.test_ms( ) 452 | } 453 | " 454 | (forward-cursor-on "main") 455 | (forward-cursor-on "main") 456 | (forward-cursor-on "( )") 457 | (forward-char 1) 458 | 459 | (let ((got (go-eldoc--documentation-function)) 460 | (expected "test_ms: ([]time.Duration) ")) 461 | (should (string= got expected))))) 462 | 463 | (ert-deftest parsing-regexp-replace-all-func () 464 | "Parsing Regexp.ReplaceAllFunc(#23)" 465 | (with-go-temp-buffer 466 | " 467 | package main 468 | import \"regexp\" 469 | 470 | var re = regexp.MustCompile(`foo`) 471 | 472 | func main() { 473 | re.ReplaceAllFunc( ) 474 | } 475 | " 476 | (forward-cursor-on "( )") 477 | (forward-char 1) 478 | 479 | (let ((got (go-eldoc--documentation-function)) 480 | (expected "ReplaceAllFunc: (src []byte, repl func([]byte) []byte) []byte")) 481 | (should (string= got expected))))) 482 | 483 | (ert-deftest function-argument-return-channel () 484 | "function argument which returns channel" 485 | (with-go-temp-buffer 486 | " 487 | package main 488 | 489 | func foo(bar func (a int, b int) chan<- string, baz int) int { 490 | } 491 | 492 | func main() { 493 | foo( ) 494 | } 495 | " 496 | (forward-cursor-on "( )") 497 | (forward-char 1) 498 | (let ((got (go-eldoc--documentation-function)) 499 | (expected "foo: (bar func(a int, b int) (chan<- string), baz int) int")) 500 | (should (string= got expected))))) 501 | 502 | (ert-deftest case-sensitive-match-function () 503 | "Match only case sensitive" 504 | (with-go-temp-buffer 505 | " 506 | package main 507 | 508 | import \"os\" 509 | 510 | func main() { 511 | os.MkDIR( ) 512 | os.Mkdir( ) 513 | } 514 | " 515 | (forward-cursor-on "( )") 516 | (forward-char 1) 517 | (should-not (go-eldoc--documentation-function)) 518 | 519 | (forward-cursor-on "( )") 520 | (forward-char 1) 521 | (should (go-eldoc--documentation-function)))) 522 | 523 | (ert-deftest array-index-issue () 524 | "Bug in array bracket" 525 | (with-go-temp-buffer 526 | " 527 | package main 528 | 529 | import \"net/http\" 530 | 531 | const USERS = []string{ 532 | \"foo\" 533 | } 534 | 535 | func main() { 536 | http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) { 537 | user := USERS[i] 538 | }) 539 | } 540 | " 541 | (forward-cursor-on "\\[i\\]") 542 | (forward-char 1) 543 | (should-not (go-eldoc--documentation-function)))) 544 | 545 | ;;; function.el end here 546 | -------------------------------------------------------------------------------- /go-eldoc.el: -------------------------------------------------------------------------------- 1 | ;;; go-eldoc.el --- eldoc 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-eldoc 7 | ;; Version: 0.30 8 | ;; Package-Requires: ((emacs "24.3") (go-mode "1.0.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 | ;; `go-eldoc.el' provides eldoc for Go language. `go-eldoc.el' shows type information 26 | ;; for variable, functions and current argument position of function. 27 | 28 | ;; To use this package, add these lines to your init.el file: 29 | ;; 30 | ;; (require 'go-eldoc) 31 | ;; (add-hook 'go-mode-hook 'go-eldoc-setup) 32 | ;; 33 | 34 | ;;; Code: 35 | 36 | (require 'cl-lib) 37 | 38 | (require 'eldoc) 39 | (require 'go-mode) 40 | (require 'thingatpt) 41 | 42 | (defgroup go-eldoc nil 43 | "Eldoc for golang" 44 | :group 'go 45 | :prefix "go-eldoc-") 46 | 47 | (defcustom go-eldoc-gocode "gocode" 48 | "gocode path" 49 | :type 'string) 50 | 51 | (defcustom go-eldoc-gocode-args nil 52 | "Additional arguments to pass to `gocode'" 53 | :type '(repeat string)) 54 | 55 | (defvar go-eldoc--builtins 56 | '(("append" . "append,,func(slice []Type, elems ...Type) []Type") 57 | ("close" . "close,,func(c chan<- Type)") 58 | ("delete" . "delete,,func(m map[Type]Type1, key Type)") 59 | ("panic" . "panic,,func(v interface{})") 60 | ("recover" . "recover,,func() interface{}") 61 | ("complex" . "complex,,func(r, i FloatType) ComplexType") 62 | ("imag" . "imag,,func(c ComplexType) FloatType") 63 | ("real" . "real,,func(c ComplexType) FloatType") 64 | ("new" . "new,,func(Type) *Type") 65 | ("cap" . "cap,,func(v Type) int") 66 | ("copy" . "copy,,func(dst, src []Type) int") 67 | ("len" . "len,,func(v Type) int"))) 68 | 69 | (defun go-eldoc--current-arg-index (curpoint) 70 | (save-excursion 71 | (let ((count 1) 72 | (start-level (go-paren-level))) 73 | (while (search-forward "," curpoint t) 74 | (when (and (not (go-in-string-or-comment-p)) 75 | (= start-level (1- (go-paren-level)))) 76 | (cl-incf count))) 77 | count))) 78 | 79 | (defun go-eldoc--count-string (str from to) 80 | (goto-char from) 81 | (cl-loop while (search-forward str to t) 82 | unless (go-in-string-or-comment-p) 83 | counting 1)) 84 | 85 | (defun go-eldoc--inside-funcall-p (from to) 86 | (save-excursion 87 | (let ((left-paren (go-eldoc--count-string "(" from to)) 88 | (right-paren (go-eldoc--count-string ")" from to))) 89 | (> left-paren right-paren)))) 90 | 91 | (defsubst go-eldoc--goto-opening-parenthesis () 92 | (and (ignore-errors (backward-up-list) t) 93 | (eql (char-after) ?\())) 94 | 95 | (defun go-eldoc--inside-anon-function-p (from to) 96 | (save-excursion 97 | (goto-char to) 98 | (when (go-eldoc--goto-opening-parenthesis) 99 | (when (char-equal (char-after) ?\{) 100 | (let ((func-start (point)) 101 | (case-fold-search nil)) 102 | (goto-char from) 103 | (re-search-forward "\\ index 0) 321 | (let ((highlighed-args (go-eldoc--highlight-index-position arg-type index))) 322 | (concat highlighed-args " " ret-type)) 323 | (let ((highlighed-rets (go-eldoc--highlight-index-position ret-type (- index) t))) 324 | (concat "(" arg-type ") " highlighed-rets)))))) 325 | 326 | (defun go-eldoc--analyze-func-signature () 327 | (let (arg-start arg-end) 328 | (when (search-forward "func(" nil t) 329 | (setq arg-start (point)) 330 | (backward-char 1) 331 | (when (ignore-errors (forward-list) t) 332 | (setq arg-end (1- (point))) 333 | (skip-chars-forward " \t") 334 | (list :type 'function 335 | :arg-type (buffer-substring-no-properties arg-start arg-end) 336 | :ret-type (buffer-substring-no-properties (point) (point-max))))))) 337 | 338 | (defun go-eldoc--analyze-type-signature () 339 | (when (search-forward "type " nil t) 340 | (list :type 'type 341 | :real-type (buffer-substring-no-properties (point) (point-max))))) 342 | 343 | (defun go-eldoc--analyze-signature (signature) 344 | (with-temp-buffer 345 | (set-syntax-table go-mode-syntax-table) 346 | (insert signature) 347 | (goto-char (point-min)) 348 | (let ((word (thing-at-point 'word))) 349 | (cond ((string= "func" word) 350 | (go-eldoc--analyze-func-signature)) 351 | ((string= "type" word) 352 | (go-eldoc--analyze-type-signature)))))) 353 | 354 | (defun go-eldoc--format-signature (funcinfo) 355 | (let ((name (plist-get funcinfo :name)) 356 | (signature (go-eldoc--analyze-signature (plist-get funcinfo :signature))) 357 | (index (plist-get funcinfo :index))) 358 | (when signature 359 | (cl-case (plist-get signature :type) 360 | (function 361 | (format "%s: %s" 362 | (propertize name 'face 'font-lock-function-name-face) 363 | (go-eldoc--highlight-argument signature index))) 364 | (type 365 | (format "%s: %s" 366 | (propertize name 'face 'font-lock-type-face) 367 | (plist-get signature :real-type))))))) 368 | 369 | (defun go-eldoc--retrieve-type (typeinfo symbol) 370 | (let ((case-fold-search nil)) 371 | (cond ((string-match (format "^%s,,var \\(.+\\)$" symbol) typeinfo) 372 | (match-string-no-properties 1 typeinfo)) 373 | ((string-match-p (format "\\`%s,,package\\s-*$" symbol) typeinfo) 374 | "package") 375 | ((string-match (format "^%s,,\\(func.+\\)$" symbol) typeinfo) 376 | (match-string-no-properties 1 typeinfo)) 377 | ((string-match (format "^%s,,\\(.+\\)$" symbol) typeinfo) 378 | (match-string-no-properties 1 typeinfo))))) 379 | 380 | (defun go-eldoc--get-cursor-info (bounds) 381 | (save-excursion 382 | (goto-char (cdr bounds)) 383 | (go-eldoc--retrieve-type 384 | (go-eldoc--invoke-autocomplete) 385 | (buffer-substring-no-properties (car bounds) (cdr bounds))))) 386 | 387 | (defun go-eldoc--retrieve-concrete-name (bounds) 388 | (save-excursion 389 | (goto-char (car bounds)) 390 | (while (looking-back "\\." (1- (point))) 391 | (backward-char 1) 392 | (skip-chars-backward "[:word:][:multibyte:]\\[\\]")) 393 | (buffer-substring-no-properties (point) (cdr bounds)))) 394 | 395 | (defun go-eldoc--bounds-of-go-symbol () 396 | (save-excursion 397 | (let (start) 398 | (skip-chars-backward "[:word:][:multibyte:]") 399 | (setq start (point)) 400 | (skip-chars-forward "[:word:][:multibyte:]") 401 | (unless (= start (point)) 402 | (cons start (point)))))) 403 | 404 | (defsubst go-eldoc--propertize-cursor-thing (bounds) 405 | (propertize (go-eldoc--retrieve-concrete-name bounds) 406 | 'face 'font-lock-variable-name-face)) 407 | 408 | (defun go-eldoc--documentation-function () 409 | (let ((funcinfo (go-eldoc--get-funcinfo))) 410 | (if funcinfo 411 | (go-eldoc--format-signature funcinfo) 412 | (let ((bounds (go-eldoc--bounds-of-go-symbol))) 413 | (when bounds 414 | (let ((curinfo (go-eldoc--get-cursor-info bounds))) 415 | (when curinfo 416 | (format "%s: %s" 417 | (go-eldoc--propertize-cursor-thing bounds) 418 | curinfo)))))))) 419 | 420 | ;;;###autoload 421 | (defun go-eldoc-setup () 422 | "Set up eldoc function and enable eldoc-mode." 423 | (interactive) 424 | (setq-local eldoc-documentation-function #'go-eldoc--documentation-function) 425 | (eldoc-mode +1)) 426 | 427 | (provide 'go-eldoc) 428 | 429 | ;;; go-eldoc.el ends here 430 | --------------------------------------------------------------------------------