├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── LICENSE ├── README.md ├── _gccgo └── package.go ├── _goremote └── goremote.go ├── _testing ├── DESC ├── README ├── all.bash ├── run.py ├── run.rb ├── run.tcl ├── test.0001 │ ├── cursor.47 │ ├── out.expected │ └── test.go.in ├── test.0002 │ ├── cursor.105 │ ├── out.expected │ └── test.go.in ├── test.0003 │ ├── cursor.552 │ ├── out.expected │ └── test.go.in ├── test.0004 │ ├── cursor.1348 │ ├── out.expected │ └── test.go.in ├── test.0005 │ ├── b.go │ ├── cursor.327 │ ├── out.expected │ └── test.go.in ├── test.0006 │ ├── b.go │ ├── cursor.286 │ ├── out.expected │ └── test.go.in ├── test.0007 │ ├── cursor.58 │ ├── out.expected │ └── test.go.in ├── test.0008 │ ├── cursor.120 │ ├── out.expected │ └── test.go.in ├── test.0009 │ ├── cursor.126 │ ├── out.expected │ └── test.go.in ├── test.0010 │ ├── cursor.104 │ ├── out.expected │ └── test.go.in ├── test.0011 │ ├── cursor.76 │ ├── out.expected │ └── test.go.in ├── test.0012 │ ├── cursor.114 │ ├── out.expected │ └── test.go.in ├── test.0013 │ ├── cursor.359 │ ├── out.expected │ └── test.go.in ├── test.0014 │ ├── cursor.191 │ ├── out.expected │ └── test.go.in ├── test.0015 │ ├── cursor.130 │ ├── out.expected │ └── test.go.in ├── test.0016 │ ├── cursor.122 │ ├── out.expected │ └── test.go.in ├── test.0017 │ ├── cursor.70 │ ├── out.expected │ └── test.go.in ├── test.0018 │ ├── cursor.355 │ ├── out.expected │ └── test.go.in ├── test.0019 │ ├── cursor.72 │ ├── out.expected │ └── test.go.in ├── test.0020 │ ├── cursor.174 │ ├── out.expected │ └── test.go.in ├── test.0021 │ ├── cursor.82 │ ├── out.expected │ └── test.go.in ├── test.0022 │ ├── cursor.79 │ ├── out.expected │ └── test.go.in ├── test.0023 │ ├── cursor.88 │ ├── out.expected │ └── test.go.in ├── test.0024 │ ├── cursor.71 │ ├── out.expected │ └── test.go.in ├── test.0025 │ ├── cursor.53 │ ├── out.expected │ └── test.go.in ├── test.0026 │ ├── cursor.164 │ ├── out.expected │ └── test.go.in ├── test.0027 │ ├── cursor.84 │ ├── out.expected │ └── test.go.in ├── test.0028 │ ├── cursor.129 │ ├── out.expected │ └── test.go.in ├── test.0029 │ ├── cursor.62 │ ├── out.expected │ └── test.go.in ├── test.0030 │ ├── cursor.85 │ ├── out.expected │ └── test.go.in ├── test.0031 │ ├── cursor.80 │ ├── out.expected │ └── test.go.in ├── test.0032 │ ├── cursor.1835 │ ├── out.expected │ └── test.go.in ├── test.0033 │ ├── cursor.138 │ ├── out.expected │ └── test.go.in ├── test.0034 │ ├── cursor.82 │ ├── out.expected │ └── test.go.in ├── test.0035 │ ├── cursor.91 │ ├── out.expected │ └── test.go.in ├── test.0036 │ ├── cursor.67 │ ├── out.expected │ └── test.go.in ├── test.0037 │ ├── cursor.139 │ ├── out.expected │ └── test.go.in ├── test.0038 │ ├── cursor.87 │ ├── out.expected │ └── test.go.in ├── test.0039 │ ├── cursor.88 │ ├── out.expected │ └── test.go.in ├── test.0040 │ ├── cursor.96 │ ├── out.expected │ └── test.go.in ├── test.0041 │ ├── cursor.140 │ ├── out.expected │ └── test.go.in ├── test.0042 │ ├── cursor.126 │ ├── out.expected │ └── test.go.in ├── test.0043 │ ├── cursor.182 │ ├── out.expected │ └── test.go.in ├── test.0044 │ ├── cursor.105 │ ├── out.expected │ └── test.go.in ├── test.0045 │ ├── cursor.51 │ ├── out.expected │ └── test.go.in ├── test.0046 │ ├── cursor.53 │ ├── out.expected │ └── test.go.in ├── test.0047 │ ├── cursor.43 │ ├── out.expected │ └── test.go.in ├── test.0048 │ ├── cursor.53 │ ├── out.expected │ └── test.go.in ├── test.0049 │ ├── cursor.44 │ ├── out.expected │ └── test.go.in ├── test.0050 │ ├── cursor.45 │ ├── out.expected │ └── test.go.in ├── test.0051 │ ├── cursor.247 │ ├── out.expected │ └── test.go.in ├── test.0052 │ ├── cursor.96 │ ├── out.expected │ └── test.go.in ├── test.0053 │ ├── cursor.215 │ ├── out.expected │ └── test.go.in ├── test.0054 │ ├── cursor.168 │ ├── out.expected │ └── test.go.in ├── test.0055 │ ├── cursor.229 │ ├── out.expected │ └── test.go.in ├── test.0056 │ ├── cursor.211 │ ├── out.expected │ └── test.go.in ├── test.0057 │ ├── cursor.56 │ ├── out.expected │ └── test.go.in ├── test.0058 │ ├── cursor.65 │ ├── out.expected │ └── test.go.in ├── test.0059 │ ├── cursor.81 │ ├── out.expected │ └── test.go.in ├── test.0060 │ ├── cursor.109 │ ├── out.expected │ └── test.go.in ├── test.0061 │ ├── cursor.61 │ ├── out.expected │ └── test.go.in ├── test.0062 │ ├── cursor.141 │ ├── out.expected │ └── test.go.in └── test.0063 │ ├── cursor.109 │ ├── out.expected │ └── test.go.in ├── autocompletecontext.go ├── autocompletefile.go ├── client.go ├── config.go ├── cursorcontext.go ├── debian ├── changelog ├── compat ├── control ├── copyright ├── docs ├── gocode.default ├── rules └── source │ └── format ├── decl.go ├── declcache.go ├── docs ├── IDE_integration.md └── autocomplete_formats.md ├── emacs-company ├── README.md └── company-go.el ├── emacs └── go-autocomplete.el ├── formatters.go ├── gocode.go ├── nvim ├── autoload │ └── gocomplete.vim ├── ftplugin │ └── go │ │ └── gocomplete.vim ├── pathogen_update.sh ├── symlink.sh └── update.sh ├── os_posix.go ├── os_windows.go ├── package.go ├── package_bin.go ├── package_ibin.go ├── package_text.go ├── pre_go17.go ├── ripper.go ├── rpc.go ├── scope.go ├── server.go ├── subl3 ├── README.md ├── gocode.py └── syntax │ ├── GoSublime-Go.tmLanguage │ ├── GoSublime-Go.tmLanguage.json │ ├── GoSublime-HTML.tmLanguage │ ├── GoSublime-HTML.tmLanguage.json │ ├── GoSublime-Template.tmLanguage │ ├── GoSublime-Template.tmLanguage.json │ └── LICENSE.md ├── type_alias_build_hack_18.go ├── type_alias_build_hack_19.go ├── utils.go └── vim ├── autoload └── gocomplete.vim ├── ftplugin └── go │ └── gocomplete.vim ├── pathogen_update.sh ├── symlink.sh └── update.sh /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.8 2 | *.a 3 | *.out 4 | gocode 5 | gocode.exe 6 | goremote 7 | gocodetest 8 | *.swp 9 | listidents 10 | showcursor 11 | showsmap 12 | rename 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2010 nsf 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /_goremote/goremote.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "go/ast" 8 | "go/parser" 9 | "go/token" 10 | "io" 11 | "os" 12 | "reflect" 13 | "strings" 14 | ) 15 | 16 | const prefix = "server_" 17 | 18 | func pretty_print_type_expr(out io.Writer, e ast.Expr) { 19 | ty := reflect.TypeOf(e) 20 | switch t := e.(type) { 21 | case *ast.StarExpr: 22 | fmt.Fprintf(out, "*") 23 | pretty_print_type_expr(out, t.X) 24 | case *ast.Ident: 25 | fmt.Fprintf(out, t.Name) 26 | case *ast.ArrayType: 27 | fmt.Fprintf(out, "[]") 28 | pretty_print_type_expr(out, t.Elt) 29 | case *ast.SelectorExpr: 30 | pretty_print_type_expr(out, t.X) 31 | fmt.Fprintf(out, ".%s", t.Sel.Name) 32 | case *ast.FuncType: 33 | fmt.Fprintf(out, "func(") 34 | pretty_print_func_field_list(out, t.Params) 35 | fmt.Fprintf(out, ")") 36 | 37 | buf := bytes.NewBuffer(make([]byte, 0, 256)) 38 | nresults := pretty_print_func_field_list(buf, t.Results) 39 | if nresults > 0 { 40 | results := buf.String() 41 | if strings.Index(results, " ") != -1 { 42 | results = "(" + results + ")" 43 | } 44 | fmt.Fprintf(out, " %s", results) 45 | } 46 | case *ast.MapType: 47 | fmt.Fprintf(out, "map[") 48 | pretty_print_type_expr(out, t.Key) 49 | fmt.Fprintf(out, "]") 50 | pretty_print_type_expr(out, t.Value) 51 | case *ast.InterfaceType: 52 | fmt.Fprintf(out, "interface{}") 53 | case *ast.Ellipsis: 54 | fmt.Fprintf(out, "...") 55 | pretty_print_type_expr(out, t.Elt) 56 | default: 57 | fmt.Fprintf(out, "\n[!!] unknown type: %s\n", ty.String()) 58 | } 59 | } 60 | 61 | func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int { 62 | count := 0 63 | if f == nil { 64 | return count 65 | } 66 | for i, field := range f.List { 67 | // names 68 | if field.Names != nil { 69 | for j, name := range field.Names { 70 | fmt.Fprintf(out, "%s", name.Name) 71 | if j != len(field.Names)-1 { 72 | fmt.Fprintf(out, ", ") 73 | } 74 | count++ 75 | } 76 | fmt.Fprintf(out, " ") 77 | } else { 78 | count++ 79 | } 80 | 81 | // type 82 | pretty_print_type_expr(out, field.Type) 83 | 84 | // , 85 | if i != len(f.List)-1 { 86 | fmt.Fprintf(out, ", ") 87 | } 88 | } 89 | return count 90 | } 91 | 92 | func pretty_print_func_field_list_using_args(out io.Writer, f *ast.FieldList) int { 93 | count := 0 94 | if f == nil { 95 | return count 96 | } 97 | for i, field := range f.List { 98 | // names 99 | if field.Names != nil { 100 | for j := range field.Names { 101 | fmt.Fprintf(out, "Arg%d", count) 102 | if j != len(field.Names)-1 { 103 | fmt.Fprintf(out, ", ") 104 | } 105 | count++ 106 | } 107 | fmt.Fprintf(out, " ") 108 | } else { 109 | count++ 110 | } 111 | 112 | // type 113 | pretty_print_type_expr(out, field.Type) 114 | 115 | // , 116 | if i != len(f.List)-1 { 117 | fmt.Fprintf(out, ", ") 118 | } 119 | } 120 | return count 121 | } 122 | 123 | func generate_struct_wrapper(out io.Writer, fun *ast.FieldList, structname, name string) int { 124 | fmt.Fprintf(out, "type %s_%s struct {\n", structname, name) 125 | argn := 0 126 | for _, field := range fun.List { 127 | fmt.Fprintf(out, "\t") 128 | // names 129 | if field.Names != nil { 130 | for j := range field.Names { 131 | fmt.Fprintf(out, "Arg%d", argn) 132 | if j != len(field.Names)-1 { 133 | fmt.Fprintf(out, ", ") 134 | } 135 | argn++ 136 | } 137 | fmt.Fprintf(out, " ") 138 | } else { 139 | fmt.Fprintf(out, "Arg%d ", argn) 140 | argn++ 141 | } 142 | 143 | // type 144 | pretty_print_type_expr(out, field.Type) 145 | 146 | // \n 147 | fmt.Fprintf(out, "\n") 148 | } 149 | fmt.Fprintf(out, "}\n") 150 | return argn 151 | } 152 | 153 | // function that is being exposed to an RPC API, but calls simple "Server_" one 154 | func generate_server_rpc_wrapper(out io.Writer, fun *ast.FuncDecl, name string, argcnt, replycnt int) { 155 | fmt.Fprintf(out, "func (r *RPC) RPC_%s(args *Args_%s, reply *Reply_%s) error {\n", 156 | name, name, name) 157 | 158 | fmt.Fprintf(out, "\t") 159 | for i := 0; i < replycnt; i++ { 160 | fmt.Fprintf(out, "reply.Arg%d", i) 161 | if i != replycnt-1 { 162 | fmt.Fprintf(out, ", ") 163 | } 164 | } 165 | fmt.Fprintf(out, " = %s(", fun.Name.Name) 166 | for i := 0; i < argcnt; i++ { 167 | fmt.Fprintf(out, "args.Arg%d", i) 168 | if i != argcnt-1 { 169 | fmt.Fprintf(out, ", ") 170 | } 171 | } 172 | fmt.Fprintf(out, ")\n") 173 | fmt.Fprintf(out, "\treturn nil\n}\n") 174 | } 175 | 176 | func generate_client_rpc_wrapper(out io.Writer, fun *ast.FuncDecl, name string, argcnt, replycnt int) { 177 | fmt.Fprintf(out, "func client_%s(cli *rpc.Client, ", name) 178 | pretty_print_func_field_list_using_args(out, fun.Type.Params) 179 | fmt.Fprintf(out, ")") 180 | 181 | buf := bytes.NewBuffer(make([]byte, 0, 256)) 182 | nresults := pretty_print_func_field_list(buf, fun.Type.Results) 183 | if nresults > 0 { 184 | results := buf.String() 185 | if strings.Index(results, " ") != -1 { 186 | results = "(" + results + ")" 187 | } 188 | fmt.Fprintf(out, " %s", results) 189 | } 190 | fmt.Fprintf(out, " {\n") 191 | fmt.Fprintf(out, "\tvar args Args_%s\n", name) 192 | fmt.Fprintf(out, "\tvar reply Reply_%s\n", name) 193 | for i := 0; i < argcnt; i++ { 194 | fmt.Fprintf(out, "\targs.Arg%d = Arg%d\n", i, i) 195 | } 196 | fmt.Fprintf(out, "\terr := cli.Call(\"RPC.RPC_%s\", &args, &reply)\n", name) 197 | fmt.Fprintf(out, "\tif err != nil {\n") 198 | fmt.Fprintf(out, "\t\tpanic(err)\n\t}\n") 199 | 200 | fmt.Fprintf(out, "\treturn ") 201 | for i := 0; i < replycnt; i++ { 202 | fmt.Fprintf(out, "reply.Arg%d", i) 203 | if i != replycnt-1 { 204 | fmt.Fprintf(out, ", ") 205 | } 206 | } 207 | fmt.Fprintf(out, "\n}\n") 208 | } 209 | 210 | func wrap_function(out io.Writer, fun *ast.FuncDecl) { 211 | name := fun.Name.Name[len(prefix):] 212 | fmt.Fprintf(out, "// wrapper for: %s\n\n", fun.Name.Name) 213 | argcnt := generate_struct_wrapper(out, fun.Type.Params, "Args", name) 214 | replycnt := generate_struct_wrapper(out, fun.Type.Results, "Reply", name) 215 | generate_server_rpc_wrapper(out, fun, name, argcnt, replycnt) 216 | generate_client_rpc_wrapper(out, fun, name, argcnt, replycnt) 217 | fmt.Fprintf(out, "\n") 218 | } 219 | 220 | func process_file(out io.Writer, filename string) { 221 | fset := token.NewFileSet() 222 | file, err := parser.ParseFile(fset, filename, nil, 0) 223 | if err != nil { 224 | panic(err) 225 | } 226 | 227 | for _, decl := range file.Decls { 228 | if fdecl, ok := decl.(*ast.FuncDecl); ok { 229 | namelen := len(fdecl.Name.Name) 230 | if namelen >= len(prefix) && fdecl.Name.Name[0:len(prefix)] == prefix { 231 | wrap_function(out, fdecl) 232 | } 233 | } 234 | } 235 | } 236 | 237 | const head = `// WARNING! Autogenerated by goremote, don't touch. 238 | 239 | package main 240 | 241 | import ( 242 | "net/rpc" 243 | ) 244 | 245 | type RPC struct { 246 | } 247 | 248 | ` 249 | 250 | func main() { 251 | flag.Parse() 252 | fmt.Fprintf(os.Stdout, head) 253 | for _, file := range flag.Args() { 254 | process_file(os.Stdout, file) 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /_testing/DESC: -------------------------------------------------------------------------------- 1 | test.0001 - basic package import (fmt) 2 | test.0002 - range statement over map variable 3 | test.0003 - type switch statement valid type case 4 | test.0004 - type switch statement default type case 5 | test.0005 - multifile package test, type inference 6 | test.0006 - multifile package test, methods 7 | test.0007 - class selector on packages (var) 8 | test.0008 - variable with anonymous type + type embedding 9 | test.0009 - same as test.0008, but more deeply 10 | test.0010 - type assertion (to *ast.ValueSpec) 11 | test.0011 - *reflect.StructValue, unexported type embedding 12 | test.0012 - type advancing, file with no import statements 13 | test.0013 - binary operators 14 | test.0014 - address of and pointer dereferences 15 | test.0015 - unary operators 16 | test.0016 - for and if else statements 17 | test.0017 - simple functions before and after cursor 18 | test.0018 - complex type inference case 19 | test.0019 - map[string]something.# case 20 | test.0020 - embedded types, method overloading (sort of) 21 | test.0021 - SelectorExpr case, uses package local scope 22 | test.0022 - range loop, but iteratable is returned by a function 23 | test.0023 - simple check for unicode awareness 24 | test.0024 - variable and the type with the same name 25 | test.0025 - built-in package "unsafe" 26 | test.0026 - more anonymous structs 27 | test.0027 - function specific variables scope issues (recv, args, results) 28 | test.0028 - the reason why I need to implement binary ops 29 | test.0029 - import to the current package scope (import . "whatever") 30 | test.0030 - typedef struct type and try to use its fields 31 | test.0031 - simple test for select clause 32 | test.0032 - import all packages (tests package parser) 33 | test.0033 - varargs type as a slice type in different contexts 34 | test.0034 - interface with methods imported from another package 35 | test.0035 - built-in "error" interface 36 | test.0036 - embedded struct in a package as an ordinary field 37 | test.0037 - slice expressions 38 | test.0038 - if init declaration inside else stmt 39 | test.0039 - addition to test 38, make sure decl doesn't leak 40 | test.0040 - anonymous return values shouldn't introduce new vars 41 | test.0041 - nested struct initialization expressions (outer) 42 | test.0042 - nested struct initialization expressions (inner) 43 | test.0043 - sequential struct initialization expressions 44 | test.0044 - struct initialization expression only suggests var names (no functions) 45 | test.0045 - if statement 46 | test.0046 - ":=" statement 47 | test.0047 - completion on struct with undefined embedded type 48 | test.0048 - completion with cursor in the middle of existing token 49 | test.0049 - anonymous struct type as a function argument 50 | test.0050 - anonymous struct pointer type as a function argument 51 | test.0051 - go parser stops parsing after 10 errors without AllErrors flag 52 | test.0052 - implicit type of a struct within slice/array literal 53 | test.0053 - type redefinition should not inherit method sets 54 | test.0054 - type alias dealiasing 55 | test.0055 - type alias inference 56 | test.0056 - type alias method propagation 57 | test.0057 - embedded interfaces 58 | test.0058 - canonical import aliases 59 | test.0059 - canonical import aliases, more complicated case (doesn't work as you might expect) 60 | test.0060 - shortcut syntax for return value types in functions 61 | test.0061 - function body vs struct literal cursor context detection 62 | test.0062 - struct type alias embedding 63 | test.0063 - fields autocompletion for a struct literal which is defined by a type alias 64 | -------------------------------------------------------------------------------- /_testing/README: -------------------------------------------------------------------------------- 1 | --== Desc ==-- 2 | 3 | This is a bunch of automated tests for gocode. 4 | 5 | Tests can be slow, because after each request gocode server runs GC. 6 | And current Go GC is slow. You won't notice that other than in tests 7 | because usually you spend some time in editor between requests and 8 | that time is wasted on a GC run, but testing app throws requests one 9 | after another and it causes GC to eat a lot of CPU. So.. don't worry 10 | about that. 11 | -------------------------------------------------------------------------------- /_testing/all.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | gocode close 3 | sleep 0.5 4 | echo "--------------------------------------------------------------------" 5 | echo "Autocompletion tests..." 6 | echo "--------------------------------------------------------------------" 7 | export XDG_CONFIG_HOME="$(mktemp -d)" 8 | ./run.rb 9 | sleep 0.5 10 | gocode close 11 | -------------------------------------------------------------------------------- /_testing/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | import os, glob, subprocess, sys 5 | 6 | total = 0 7 | ok = 0 8 | fail = 0 9 | expected_fail = 0 10 | 11 | RED = "\033[0;31m" 12 | GREEN = "\033[0;32m" 13 | YELLOW = "\033[0;33m" 14 | NC = "\033[0m" 15 | 16 | OK = GREEN + "PASS!" + NC 17 | FAIL = RED + "FAIL!" + NC 18 | EXPECTED = YELLOW + "EXPECTED: " + NC 19 | 20 | # name of the test + commentary (why it is expected to fail) 21 | expected_to_fail = { 22 | } 23 | 24 | def run_test(t): 25 | global total, ok, fail, expected_fail 26 | total += 1 27 | c = glob.glob(t + "/cursor.*")[0] 28 | cursorpos = os.path.splitext(c)[1][1:] 29 | try: 30 | with open(t + "/out.expected", "r") as f: 31 | outexpected = f.read() 32 | except: 33 | outexpected = "To be determined" 34 | filename = t + "/test.go.in" 35 | gocode = subprocess.Popen(["gocode", "-in", filename, "autocomplete", filename, cursorpos], 36 | shell=False, stdout=subprocess.PIPE) 37 | out = gocode.communicate()[0] 38 | if out != outexpected: 39 | if t in expected_to_fail: 40 | print t + ": " + FAIL + " " + EXPECTED + expected_to_fail[t] 41 | expected_fail += 1 42 | else: 43 | print t + ": " + FAIL 44 | print "--------------------------------------------------------" 45 | print "Got:\n" + out 46 | print "--------------------------------------------------------" 47 | print "Expected:\n" + outexpected 48 | print "--------------------------------------------------------" 49 | fail += 1 50 | else: 51 | print t + ": " + OK 52 | ok += 1 53 | 54 | if len(sys.argv) == 2: 55 | run_test(sys.argv[1]) 56 | else: 57 | for t in sorted(glob.glob("test.*")): 58 | run_test(t) 59 | 60 | print "\nSummary (total: %d):" % total 61 | print GREEN + " PASS" + NC + ": %d" % ok 62 | print RED +" FAIL" + NC + ": %d (unexpected failures)" % fail 63 | 64 | if fail == 0: 65 | print GREEN + "████████████████████████████████████████████████████████████████████" + NC 66 | else: 67 | print RED + "████████████████████████████████████████████████████████████████████" + NC 68 | -------------------------------------------------------------------------------- /_testing/run.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | RED = "\033[0;31m" 5 | GRN = "\033[0;32m" 6 | NC = "\033[0m" 7 | 8 | PASS = "#{GRN}PASS!#{NC}" 9 | FAIL = "#{RED}FAIL!#{NC}" 10 | 11 | Stats = Struct.new :total, :ok, :fail 12 | $stats = Stats.new 0, 0, 0 13 | 14 | def print_fail_report(t, out, outexpected) 15 | puts "#{t}: #{FAIL}" 16 | puts "-"*65 17 | puts "Got:\n#{out}" 18 | puts "-"*65 19 | puts "Expected:\n#{outexpected}" 20 | puts "-"*65 21 | end 22 | 23 | def print_pass_report(t) 24 | puts "#{t}: #{PASS}" 25 | end 26 | 27 | def print_stats 28 | puts "\nSummary (total: #{$stats.total})" 29 | puts "#{GRN} PASS#{NC}: #{$stats.ok}" 30 | puts "#{RED} FAIL#{NC}: #{$stats.fail}" 31 | puts "#{$stats.fail == 0 ? GRN : RED}#{"█"*72}#{NC}" 32 | end 33 | 34 | def run_test(t) 35 | $stats.total += 1 36 | 37 | cursorpos = Dir["#{t}/cursor.*"].map{|d| File.extname(d)[1..-1]}.first 38 | outexpected = IO.read("#{t}/out.expected") rescue "To be determined" 39 | filename = "#{t}/test.go.in" 40 | 41 | out = %x[gocode -in #{filename} autocomplete #{filename} #{cursorpos}] 42 | 43 | if out != outexpected then 44 | print_fail_report(t, out, outexpected) 45 | $stats.fail += 1 46 | else 47 | print_pass_report(t) 48 | $stats.ok += 1 49 | end 50 | end 51 | 52 | if ARGV.one? 53 | run_test ARGV[0] 54 | else 55 | Dir["test.*"].sort.each do |t| 56 | run_test t 57 | end 58 | end 59 | 60 | print_stats 61 | -------------------------------------------------------------------------------- /_testing/run.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tclsh 2 | 3 | set red "\033\[0;31m" 4 | set grn "\033\[0;32m" 5 | set nc "\033\[0m" 6 | 7 | set pass "${grn}PASS!${nc}" 8 | set fail "${red}FAIL!${nc}" 9 | 10 | set stats.total 0 11 | set stats.ok 0 12 | set stats.fail 0 13 | 14 | proc print_fail_report {t out expected} { 15 | global fail 16 | 17 | set hr [join [lrepeat 65 "-"] ""] 18 | puts "${t}: ${fail}" 19 | puts $hr 20 | puts "Got:\n${out}" 21 | puts $hr 22 | puts "Expected:\n${expected}" 23 | puts $hr 24 | } 25 | 26 | proc print_pass_report {t} { 27 | global pass 28 | 29 | puts "${t}: ${pass}" 30 | } 31 | 32 | proc print_stats {} { 33 | global red grn nc stats.total stats.ok stats.fail 34 | 35 | set hr [join [lrepeat 72 "█"] ""] 36 | set hrcol [expr {${stats.fail} ? $red : $grn}] 37 | puts "\nSummary (total: ${stats.total})" 38 | puts "${grn} PASS${nc}: ${stats.ok}" 39 | puts "${red} FAIL${nc}: ${stats.fail}" 40 | puts "${hrcol}${hr}${nc}" 41 | } 42 | 43 | proc read_file {filename} { 44 | set f [open $filename r] 45 | set data [read $f] 46 | close $f 47 | return $data 48 | } 49 | 50 | proc run_test {t} { 51 | global stats.total stats.ok stats.fail 52 | 53 | incr stats.total 54 | set cursorpos [string range [file extension [glob "${t}/cursor.*"]] 1 end] 55 | set expected [read_file "${t}/out.expected"] 56 | set filename "${t}/test.go.in" 57 | 58 | set out [read_file "| gocode -in ${filename} autocomplete ${filename} ${cursorpos}"] 59 | if {$out eq $expected} { 60 | print_pass_report $t 61 | incr stats.ok 62 | } else { 63 | print_fail_report $t $out $expected 64 | incr stats.fail 65 | } 66 | } 67 | 68 | if {$argc == 1} { 69 | run_test $argv 70 | } else { 71 | foreach t [lsort [glob test.*]] { 72 | run_test $t 73 | } 74 | } 75 | 76 | print_stats 77 | 78 | 79 | -------------------------------------------------------------------------------- /_testing/test.0001/cursor.47: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0001/cursor.47 -------------------------------------------------------------------------------- /_testing/test.0001/out.expected: -------------------------------------------------------------------------------- 1 | Found 25 candidates: 2 | func Errorf(format string, a ...interface{}) error 3 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) 4 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 5 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 6 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) 7 | func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 8 | func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 9 | func Print(a ...interface{}) (n int, err error) 10 | func Printf(format string, a ...interface{}) (n int, err error) 11 | func Println(a ...interface{}) (n int, err error) 12 | func Scan(a ...interface{}) (n int, err error) 13 | func Scanf(format string, a ...interface{}) (n int, err error) 14 | func Scanln(a ...interface{}) (n int, err error) 15 | func Sprint(a ...interface{}) string 16 | func Sprintf(format string, a ...interface{}) string 17 | func Sprintln(a ...interface{}) string 18 | func Sscan(str string, a ...interface{}) (n int, err error) 19 | func Sscanf(str string, format string, a ...interface{}) (n int, err error) 20 | func Sscanln(str string, a ...interface{}) (n int, err error) 21 | type Formatter interface 22 | type GoStringer interface 23 | type ScanState interface 24 | type Scanner interface 25 | type State interface 26 | type Stringer interface 27 | -------------------------------------------------------------------------------- /_testing/test.0001/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0002/cursor.105: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0002/cursor.105 -------------------------------------------------------------------------------- /_testing/test.0002/out.expected: -------------------------------------------------------------------------------- 1 | Found 5 candidates: 2 | func main() 3 | package os 4 | var key string 5 | var test map[string]os.Error 6 | var value os.Error 7 | -------------------------------------------------------------------------------- /_testing/test.0002/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | 5 | var test map[string]os.Error 6 | 7 | func main() { 8 | for key, value := range test { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /_testing/test.0003/cursor.552: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0003/cursor.552 -------------------------------------------------------------------------------- /_testing/test.0003/out.expected: -------------------------------------------------------------------------------- 1 | Found 7 candidates: 2 | func End() token.Pos 3 | func IsExported() bool 4 | func Pos() token.Pos 5 | func String() string 6 | var Name string 7 | var NamePos token.Pos 8 | var Obj *ast.Object 9 | -------------------------------------------------------------------------------- /_testing/test.0003/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/ast" 5 | "io" 6 | ) 7 | 8 | func PrettyPrintTypeExpr(out io.Writer, e ast.Expr) { 9 | switch t := e.(type) { 10 | case *ast.StarExpr: 11 | fmt.Fprintf(out, "*") 12 | PrettyPrintTypeExpr(out, t.X) 13 | case *ast.Ident: 14 | // ast.Ident type decl as a reminder (note embedded type): 15 | // 16 | // type Ident struct { 17 | // token.Position // identifier position 18 | // Obj *Object // denoted object 19 | // } 20 | // 21 | // Correct type inference in complex type switch statements + 22 | // support for type embedding 23 | fmt.Fprintf(out, t.Name()) 24 | t. 25 | case *ast.ArrayType: 26 | fmt.Fprintf(out, "[]") 27 | PrettyPrintTypeExpr(out, t.Elt) 28 | case *ast.SelectorExpr: 29 | PrettyPrintTypeExpr(out, t.X) 30 | fmt.Fprintf(out, ".%s", t.Sel.Name()) 31 | case *ast.FuncType: 32 | // SKIP THIS FOR DEMO 33 | case *ast.MapType: 34 | fmt.Fprintf(out, "map[") 35 | PrettyPrintTypeExpr(out, t.Key) 36 | fmt.Fprintf(out, "]") 37 | PrettyPrintTypeExpr(out, t.Value) 38 | case *ast.InterfaceType: 39 | fmt.Fprintf(out, "interface{}") 40 | case *ast.Ellipsis: 41 | fmt.Fprintf(out, "...") 42 | PrettyPrintTypeExpr(out, t.Elt) 43 | case *ast.StructType: 44 | fmt.Fprintf(out, "struct") 45 | case *ast.ChanType: 46 | switch t.Dir { 47 | case ast.RECV: 48 | fmt.Fprintf(out, "<-chan ") 49 | case ast.SEND: 50 | fmt.Fprintf(out, "chan<- ") 51 | case ast.SEND | ast.RECV: 52 | fmt.Fprintf(out, "chan ") 53 | } 54 | PrettyPrintTypeExpr(out, t.Value) 55 | default: 56 | panic("OMGWTFBBQ!") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /_testing/test.0004/cursor.1348: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0004/cursor.1348 -------------------------------------------------------------------------------- /_testing/test.0004/out.expected: -------------------------------------------------------------------------------- 1 | Found 6 candidates: 2 | func PrettyPrintTypeExpr(out io.Writer, e ast.Expr) 3 | package ast 4 | package io 5 | var e ast.Expr 6 | var out io.Writer 7 | var t ast.Expr 8 | -------------------------------------------------------------------------------- /_testing/test.0004/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/ast" 5 | "io" 6 | ) 7 | 8 | func PrettyPrintTypeExpr(out io.Writer, e ast.Expr) { 9 | switch t := e.(type) { 10 | case *ast.StarExpr: 11 | fmt.Fprintf(out, "*") 12 | PrettyPrintTypeExpr(out, t.X) 13 | case *ast.Ident: 14 | // ast.Ident type decl as a reminder (note embedded type): 15 | // 16 | // type Ident struct { 17 | // token.Position // identifier position 18 | // Obj *Object // denoted object 19 | // } 20 | // 21 | // Correct type inference in complex type switch statements + 22 | // support for type embedding 23 | fmt.Fprintf(out, t.Name()) 24 | case *ast.ArrayType: 25 | fmt.Fprintf(out, "[]") 26 | PrettyPrintTypeExpr(out, t.Elt) 27 | case *ast.SelectorExpr: 28 | PrettyPrintTypeExpr(out, t.X) 29 | fmt.Fprintf(out, ".%s", t.Sel.Name()) 30 | case *ast.FuncType: 31 | // SKIP THIS FOR DEMO 32 | case *ast.MapType: 33 | fmt.Fprintf(out, "map[") 34 | PrettyPrintTypeExpr(out, t.Key) 35 | fmt.Fprintf(out, "]") 36 | PrettyPrintTypeExpr(out, t.Value) 37 | case *ast.InterfaceType: 38 | fmt.Fprintf(out, "interface{}") 39 | case *ast.Ellipsis: 40 | fmt.Fprintf(out, "...") 41 | PrettyPrintTypeExpr(out, t.Elt) 42 | case *ast.StructType: 43 | fmt.Fprintf(out, "struct") 44 | case *ast.ChanType: 45 | switch t.Dir { 46 | case ast.RECV: 47 | fmt.Fprintf(out, "<-chan ") 48 | case ast.SEND: 49 | fmt.Fprintf(out, "chan<- ") 50 | case ast.SEND | ast.RECV: 51 | fmt.Fprintf(out, "chan ") 52 | } 53 | PrettyPrintTypeExpr(out, t.Value) 54 | default: 55 | 56 | panic("OMGWTFBBQ!") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /_testing/test.0005/b.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // this is a file 'a.go' 4 | 5 | import ( 6 | superos "os" 7 | ) 8 | 9 | func B() superos.Error { 10 | return nil 11 | } 12 | 13 | // notice how changing type of a return function in one file, 14 | // the inferred type of a variable in another file changes also 15 | 16 | func (t *Tester) SetC() { 17 | t.c = 31337 18 | } 19 | 20 | func (t *Tester) SetD() { 21 | t.d = 31337 22 | } 23 | 24 | // support for multifile packages, including correct namespace handling 25 | -------------------------------------------------------------------------------- /_testing/test.0005/cursor.327: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0005/cursor.327 -------------------------------------------------------------------------------- /_testing/test.0005/out.expected: -------------------------------------------------------------------------------- 1 | Found 5 candidates: 2 | func A() localos.Error 3 | func B() superos.Error 4 | package localos 5 | type Tester struct 6 | var test superos.Error 7 | -------------------------------------------------------------------------------- /_testing/test.0005/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // this is a file 'a.go' 4 | 5 | import ( 6 | localos "os" 7 | ) 8 | 9 | func A() localos.Error { 10 | return nil 11 | } 12 | 13 | // B() is defined in file 'b.go' 14 | var test = B() 15 | 16 | type Tester struct { 17 | a, b, c, d int 18 | } 19 | 20 | func (t *Tester) SetA() { 21 | t.a = 31337 22 | } 23 | 24 | func (t *Tester) SetB() { 25 | t.b = 31337 26 | } 27 | 28 | // methods SetC and SetD are defined in 'b.go' 29 | 30 | -------------------------------------------------------------------------------- /_testing/test.0006/b.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // this is a file 'a.go' 4 | 5 | import ( 6 | superos "os" 7 | ) 8 | 9 | func B() superos.Error { 10 | return nil 11 | } 12 | 13 | // notice how changing type of a return function in one file, 14 | // the inferred type of a variable in another file changes also 15 | 16 | func (t *Tester) SetC() { 17 | t.c = 31337 18 | } 19 | 20 | func (t *Tester) SetD() { 21 | t.d = 31337 22 | } 23 | 24 | // support for multifile packages, including correct namespace handling 25 | -------------------------------------------------------------------------------- /_testing/test.0006/cursor.286: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0006/cursor.286 -------------------------------------------------------------------------------- /_testing/test.0006/out.expected: -------------------------------------------------------------------------------- 1 | Found 8 candidates: 2 | func SetA() 3 | func SetB() 4 | func SetC() 5 | func SetD() 6 | var a int 7 | var b int 8 | var c int 9 | var d int 10 | -------------------------------------------------------------------------------- /_testing/test.0006/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // this is a file 'a.go' 4 | 5 | import ( 6 | localos "os" 7 | ) 8 | 9 | func A() localos.Error { 10 | return nil 11 | } 12 | 13 | // B() is defined in file 'b.go' 14 | var test = B() 15 | 16 | type Tester struct { 17 | a, b, c, d int 18 | } 19 | 20 | func (t *Tester) SetA() { 21 | t.a = 31337 22 | } 23 | 24 | func (t *Tester) SetB() { 25 | t.b = 31337 26 | } 27 | 28 | Tester. 29 | 30 | // methods SetC and SetD are defined in 'b.go' 31 | -------------------------------------------------------------------------------- /_testing/test.0007/cursor.58: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0007/cursor.58 -------------------------------------------------------------------------------- /_testing/test.0007/out.expected: -------------------------------------------------------------------------------- 1 | Found 5 candidates: 2 | var ForkLock sync.RWMutex 3 | var SocketDisableIPv6 bool 4 | var Stderr int 5 | var Stdin int 6 | var Stdout int 7 | -------------------------------------------------------------------------------- /_testing/test.0007/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "syscall" 4 | 5 | func main() { 6 | syscall.var 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0008/cursor.120: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0008/cursor.120 -------------------------------------------------------------------------------- /_testing/test.0008/out.expected: -------------------------------------------------------------------------------- 1 | Found 6 candidates: 2 | func Lock() 3 | func Unlock() 4 | var Mutex sync.Mutex 5 | var data map[string][]string 6 | var path string 7 | var time int64 8 | -------------------------------------------------------------------------------- /_testing/test.0008/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | var hosts struct { 6 | sync.Mutex 7 | data map[string][]string 8 | time int64 9 | path string 10 | } 11 | 12 | hosts. 13 | 14 | func main() { 15 | } 16 | -------------------------------------------------------------------------------- /_testing/test.0009/cursor.126: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0009/cursor.126 -------------------------------------------------------------------------------- /_testing/test.0009/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func Lock() 3 | func Unlock() 4 | -------------------------------------------------------------------------------- /_testing/test.0009/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | var hosts struct { 6 | sync.Mutex 7 | data map[string][]string 8 | time int64 9 | path string 10 | } 11 | 12 | hosts.Mutex. 13 | 14 | func main() { 15 | } 16 | -------------------------------------------------------------------------------- /_testing/test.0010/cursor.104: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0010/cursor.104 -------------------------------------------------------------------------------- /_testing/test.0010/out.expected: -------------------------------------------------------------------------------- 1 | Found 7 candidates: 2 | func End() token.Pos 3 | func Pos() token.Pos 4 | var Comment *ast.CommentGroup 5 | var Doc *ast.CommentGroup 6 | var Names []*ast.Ident 7 | var Type ast.Expr 8 | var Values []ast.Expr 9 | -------------------------------------------------------------------------------- /_testing/test.0010/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "go/ast" 4 | 5 | func main() { 6 | var gd *ast.GenDecl 7 | v := gd.Specs[0].(*ast.ValueSpec) 8 | v. 9 | } 10 | -------------------------------------------------------------------------------- /_testing/test.0011/cursor.76: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0011/cursor.76 -------------------------------------------------------------------------------- /_testing/test.0011/out.expected: -------------------------------------------------------------------------------- 1 | Found 59 candidates: 2 | func Addr() reflect.Value 3 | func Bool() bool 4 | func Bytes() []byte 5 | func Call(in []reflect.Value) []reflect.Value 6 | func CallSlice(in []reflect.Value) []reflect.Value 7 | func CanAddr() bool 8 | func CanInterface() bool 9 | func CanSet() bool 10 | func Cap() int 11 | func Close() 12 | func Complex() complex128 13 | func Convert(t reflect.Type) reflect.Value 14 | func Elem() reflect.Value 15 | func Field(i int) reflect.Value 16 | func FieldByIndex(index []int) reflect.Value 17 | func FieldByName(name string) reflect.Value 18 | func FieldByNameFunc(match func(string) bool) reflect.Value 19 | func Float() float64 20 | func Index(i int) reflect.Value 21 | func Int() int64 22 | func Interface() (i interface{}) 23 | func InterfaceData() [2]uintptr 24 | func IsNil() bool 25 | func IsValid() bool 26 | func Kind() reflect.Kind 27 | func Len() int 28 | func MapIndex(key reflect.Value) reflect.Value 29 | func MapKeys() []reflect.Value 30 | func Method(i int) reflect.Value 31 | func MethodByName(name string) reflect.Value 32 | func NumField() int 33 | func NumMethod() int 34 | func OverflowComplex(x complex128) bool 35 | func OverflowFloat(x float64) bool 36 | func OverflowInt(x int64) bool 37 | func OverflowUint(x uint64) bool 38 | func Pointer() uintptr 39 | func Recv() (x reflect.Value, ok bool) 40 | func Send(x reflect.Value) 41 | func Set(x reflect.Value) 42 | func SetBool(x bool) 43 | func SetBytes(x []byte) 44 | func SetCap(n int) 45 | func SetComplex(x complex128) 46 | func SetFloat(x float64) 47 | func SetInt(x int64) 48 | func SetLen(n int) 49 | func SetMapIndex(key reflect.Value, val reflect.Value) 50 | func SetPointer(x unsafe.Pointer) 51 | func SetString(x string) 52 | func SetUint(x uint64) 53 | func Slice(i int, j int) reflect.Value 54 | func Slice3(i int, j int, k int) reflect.Value 55 | func String() string 56 | func TryRecv() (x reflect.Value, ok bool) 57 | func TrySend(x reflect.Value) bool 58 | func Type() reflect.Type 59 | func Uint() uint64 60 | func UnsafeAddr() uintptr 61 | -------------------------------------------------------------------------------- /_testing/test.0011/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "reflect" 4 | 5 | func main() { 6 | var test reflect.Value 7 | test. 8 | } 9 | -------------------------------------------------------------------------------- /_testing/test.0012/cursor.114: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0012/cursor.114 -------------------------------------------------------------------------------- /_testing/test.0012/out.expected: -------------------------------------------------------------------------------- 1 | Found 6 candidates: 2 | func main() 3 | type MyMap map[string]int 4 | var key string 5 | var m MyMap 6 | var value int 7 | var z int 8 | -------------------------------------------------------------------------------- /_testing/test.0012/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type MyMap map[string]int 4 | 5 | func main() { 6 | var m MyMap 7 | for key, value := range m { 8 | z := m["15"] 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /_testing/test.0013/cursor.359: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0013/cursor.359 -------------------------------------------------------------------------------- /_testing/test.0013/out.expected: -------------------------------------------------------------------------------- 1 | Found 24 candidates: 2 | func main() 3 | var a int 4 | var add int 5 | var and int 6 | var andnot int 7 | var b int 8 | var c bool 9 | var d bool 10 | var div int 11 | var eq bool 12 | var geq bool 13 | var greater bool 14 | var leq bool 15 | var less bool 16 | var logand bool 17 | var logor bool 18 | var mul int 19 | var neq bool 20 | var or int 21 | var rem int 22 | var shl int 23 | var shr int 24 | var sub int 25 | var xor int 26 | -------------------------------------------------------------------------------- /_testing/test.0013/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var a, b int 5 | add := a + b 6 | sub := a - b 7 | mul := a * b 8 | div := a / b 9 | or := a | b 10 | xor := a ^ b 11 | rem := a % b 12 | shr := a >> uint(b) 13 | shl := a << uint(b) 14 | and := a & b 15 | andnot := a &^ b 16 | 17 | eq := a == b 18 | neq := a != b 19 | less := a < b 20 | leq := a <= b 21 | greater := a > b 22 | geq := a >= b 23 | 24 | var c, d bool 25 | logor := c || d 26 | logand := c && d 27 | 28 | } 29 | -------------------------------------------------------------------------------- /_testing/test.0014/cursor.191: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0014/cursor.191 -------------------------------------------------------------------------------- /_testing/test.0014/out.expected: -------------------------------------------------------------------------------- 1 | Found 11 candidates: 2 | func main() 3 | type MyPtrInt *int 4 | var a *int 5 | var aa int 6 | var b int 7 | var bb *MyPtrInt 8 | var c *int 9 | var d **int 10 | var megaptr **int 11 | var superint int 12 | var typeptr MyPtrInt 13 | -------------------------------------------------------------------------------- /_testing/test.0014/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type MyPtrInt *int 4 | 5 | func main() { 6 | var megaptr **int 7 | a := *megaptr 8 | b := *a 9 | 10 | var superint int 11 | c := &superint 12 | d := &c 13 | 14 | var typeptr MyPtrInt 15 | aa := *typeptr 16 | bb := &typeptr 17 | 18 | } 19 | -------------------------------------------------------------------------------- /_testing/test.0015/cursor.130: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0015/cursor.130 -------------------------------------------------------------------------------- /_testing/test.0015/out.expected: -------------------------------------------------------------------------------- 1 | Found 9 candidates: 2 | func main() 3 | var a int 4 | var arro bool 5 | var b bool 6 | var c chan bool 7 | var uadd int 8 | var unot bool 9 | var usub int 10 | var uxor bool 11 | -------------------------------------------------------------------------------- /_testing/test.0015/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var a int 5 | var b bool 6 | var c chan bool 7 | uadd := +a 8 | usub := -a 9 | unot := !b 10 | uxor := ^b 11 | arro := <-c 12 | 13 | } 14 | -------------------------------------------------------------------------------- /_testing/test.0016/cursor.122: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0016/cursor.122 -------------------------------------------------------------------------------- /_testing/test.0016/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | func main() 3 | var a int 4 | var b string 5 | var d bool 6 | -------------------------------------------------------------------------------- /_testing/test.0016/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var a int 5 | for { 6 | var b string 7 | if a == len(b) { 8 | var c bool 9 | } else { 10 | var d bool 11 | 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /_testing/test.0017/cursor.70: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0017/cursor.70 -------------------------------------------------------------------------------- /_testing/test.0017/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | func a(a, b, c int) int 3 | func b(a, b, c string) string 4 | func main() 5 | -------------------------------------------------------------------------------- /_testing/test.0017/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func a(a, b, c int) int { 4 | return 123 5 | } 6 | 7 | func main() { 8 | 9 | } 10 | 11 | func b(a, b, c string) string { 12 | return "abc" 13 | } 14 | 15 | -------------------------------------------------------------------------------- /_testing/test.0018/cursor.355: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0018/cursor.355 -------------------------------------------------------------------------------- /_testing/test.0018/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func Bark() 3 | var Legs int 4 | -------------------------------------------------------------------------------- /_testing/test.0018/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // just a dummy example 8 | type Dog struct { 9 | Legs int 10 | } 11 | 12 | func (d *Dog) Bark() { 13 | fmt.Printf("Bark!\n") 14 | } 15 | 16 | // another one 17 | type Test struct { 18 | // map of slices of pointer to a *Dog 19 | MoreTests map[string][]**Dog 20 | } 21 | 22 | func (t *Test) GetMe() *Test { 23 | return t 24 | } 25 | 26 | func main() { 27 | t := new(Test) 28 | (*t.GetMe().MoreTests["blabla"][10]). 29 | } 30 | -------------------------------------------------------------------------------- /_testing/test.0019/cursor.72: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0019/cursor.72 -------------------------------------------------------------------------------- /_testing/test.0019/out.expected: -------------------------------------------------------------------------------- 1 | Found 15 candidates: 2 | const BestCompression 3 | const BestSpeed 4 | const DefaultCompression 5 | const HuffmanOnly 6 | const NoCompression 7 | func NewReader(r io.Reader) (io.ReadCloser, error) 8 | func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) 9 | func NewWriter(w io.Writer) *zlib.Writer 10 | func NewWriterLevel(w io.Writer, level int) (*zlib.Writer, error) 11 | func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*zlib.Writer, error) 12 | type Resetter interface 13 | type Writer struct 14 | var ErrChecksum error 15 | var ErrDictionary error 16 | var ErrHeader error 17 | -------------------------------------------------------------------------------- /_testing/test.0019/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "compress/zlib" 4 | 5 | func main() { 6 | var b map[int]zlib. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0020/cursor.174: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0020/cursor.174 -------------------------------------------------------------------------------- /_testing/test.0020/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | func Lock() 3 | func Unlock() 4 | var Dummy Dummy 5 | var Mutex sync.Mutex 6 | -------------------------------------------------------------------------------- /_testing/test.0020/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | type Dummy struct { 6 | sync.Mutex 7 | } 8 | 9 | type Bar struct { 10 | Dummy 11 | } 12 | 13 | func (b *Bar) Lock() { 14 | } 15 | 16 | func (b *Bar) Unlock() { 17 | } 18 | 19 | func main() { 20 | var b Bar 21 | b. 22 | } 23 | -------------------------------------------------------------------------------- /_testing/test.0021/cursor.82: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0021/cursor.82 -------------------------------------------------------------------------------- /_testing/test.0021/out.expected: -------------------------------------------------------------------------------- 1 | Found 7 candidates: 2 | func End() token.Pos 3 | func IsExported() bool 4 | func Pos() token.Pos 5 | func String() string 6 | var Name string 7 | var NamePos token.Pos 8 | var Obj *ast.Object 9 | -------------------------------------------------------------------------------- /_testing/test.0021/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "go/ast" 4 | 5 | func main() { 6 | var test *ast.ImportSpec 7 | test.Name. 8 | } 9 | -------------------------------------------------------------------------------- /_testing/test.0022/cursor.79: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0022/cursor.79 -------------------------------------------------------------------------------- /_testing/test.0022/out.expected: -------------------------------------------------------------------------------- 1 | Found 5 candidates: 2 | func getMap() map[string]os.Error 3 | func main() 4 | package os 5 | var key string 6 | var value os.Error 7 | -------------------------------------------------------------------------------- /_testing/test.0022/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | 5 | func main() { 6 | for key, value := range getMap() { 7 | 8 | } 9 | } 10 | 11 | func getMap() map[string]os.Error { 12 | // simply to trick type inference 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /_testing/test.0023/cursor.88: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0023/cursor.88 -------------------------------------------------------------------------------- /_testing/test.0023/out.expected: -------------------------------------------------------------------------------- 1 | Found 25 candidates: 2 | func Errorf(format string, a ...interface{}) error 3 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) 4 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 5 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 6 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) 7 | func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 8 | func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 9 | func Print(a ...interface{}) (n int, err error) 10 | func Printf(format string, a ...interface{}) (n int, err error) 11 | func Println(a ...interface{}) (n int, err error) 12 | func Scan(a ...interface{}) (n int, err error) 13 | func Scanf(format string, a ...interface{}) (n int, err error) 14 | func Scanln(a ...interface{}) (n int, err error) 15 | func Sprint(a ...interface{}) string 16 | func Sprintf(format string, a ...interface{}) string 17 | func Sprintln(a ...interface{}) string 18 | func Sscan(str string, a ...interface{}) (n int, err error) 19 | func Sscanf(str string, format string, a ...interface{}) (n int, err error) 20 | func Sscanln(str string, a ...interface{}) (n int, err error) 21 | type Formatter interface 22 | type GoStringer interface 23 | type ScanState interface 24 | type Scanner interface 25 | type State interface 26 | type Stringer interface 27 | -------------------------------------------------------------------------------- /_testing/test.0023/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Simple check for unicode awareness 4 | 5 | import ъ "fmt" 6 | 7 | func main() { 8 | ъ. 9 | } 10 | -------------------------------------------------------------------------------- /_testing/test.0024/cursor.71: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0024/cursor.71 -------------------------------------------------------------------------------- /_testing/test.0024/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var a int 3 | var b int 4 | var c int 5 | -------------------------------------------------------------------------------- /_testing/test.0024/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type X struct { 4 | a,b,c int 5 | } 6 | 7 | func main() { 8 | var X *X 9 | X. 10 | } 11 | -------------------------------------------------------------------------------- /_testing/test.0025/cursor.53: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0025/cursor.53 -------------------------------------------------------------------------------- /_testing/test.0025/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | func Alignof(any) uintptr 3 | func Offsetof(any) uintptr 4 | func Sizeof(any) uintptr 5 | type Pointer uintptr 6 | -------------------------------------------------------------------------------- /_testing/test.0025/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "unsafe" 4 | 5 | func main() { 6 | unsafe. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0026/cursor.164: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0026/cursor.164 -------------------------------------------------------------------------------- /_testing/test.0026/out.expected: -------------------------------------------------------------------------------- 1 | Found 7 candidates: 2 | func main() 3 | var A struct 4 | var B struct 5 | var C struct 6 | var a int 7 | var d int 8 | var g int 9 | -------------------------------------------------------------------------------- /_testing/test.0026/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var A = struct { a, b, c int }{1,2,3} 4 | var B struct { d, e, f int } 5 | 6 | func main() { 7 | C := struct { g, h, i int }{1,2,3} 8 | 9 | a := A.a 10 | d := B.d 11 | g := C.g 12 | 13 | } 14 | -------------------------------------------------------------------------------- /_testing/test.0027/cursor.84: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0027/cursor.84 -------------------------------------------------------------------------------- /_testing/test.0027/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func String() 3 | var name string 4 | -------------------------------------------------------------------------------- /_testing/test.0027/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type file struct { 4 | name string 5 | } 6 | 7 | func (file *file) String() { 8 | file. 9 | return file.name 10 | } 11 | 12 | func main() { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /_testing/test.0028/cursor.129: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0028/cursor.129 -------------------------------------------------------------------------------- /_testing/test.0028/out.expected: -------------------------------------------------------------------------------- 1 | Found 1 candidates: 2 | func PowerOfTwo() int 3 | -------------------------------------------------------------------------------- /_testing/test.0028/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type X int 4 | 5 | func (x X) PowerOfTwo() int { 6 | return int(x * x) 7 | } 8 | 9 | func main() { 10 | a := X(56) 11 | i := a + 67 12 | j := ^i 13 | j. 14 | } 15 | -------------------------------------------------------------------------------- /_testing/test.0029/cursor.62: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0029/cursor.62 -------------------------------------------------------------------------------- /_testing/test.0029/out.expected: -------------------------------------------------------------------------------- 1 | Found 27 candidates: 2 | func Errorf(format string, a ...interface{}) error 3 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) 4 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 5 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 6 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) 7 | func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 8 | func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 9 | func Print(a ...interface{}) (n int, err error) 10 | func Printf(format string, a ...interface{}) (n int, err error) 11 | func Println(a ...interface{}) (n int, err error) 12 | func Scan(a ...interface{}) (n int, err error) 13 | func Scanf(format string, a ...interface{}) (n int, err error) 14 | func Scanln(a ...interface{}) (n int, err error) 15 | func Sprint(a ...interface{}) string 16 | func Sprintf(format string, a ...interface{}) string 17 | func Sprintln(a ...interface{}) string 18 | func Sscan(str string, a ...interface{}) (n int, err error) 19 | func Sscanf(str string, format string, a ...interface{}) (n int, err error) 20 | func Sscanln(str string, a ...interface{}) (n int, err error) 21 | func main() 22 | type Formatter interface 23 | type GoStringer interface 24 | type ScanState interface 25 | type Scanner interface 26 | type State interface 27 | type Stringer interface 28 | var a Formatter 29 | -------------------------------------------------------------------------------- /_testing/test.0029/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import . "fmt" 4 | 5 | func main() { 6 | var a Formatter 7 | 8 | } 9 | -------------------------------------------------------------------------------- /_testing/test.0030/cursor.85: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0030/cursor.85 -------------------------------------------------------------------------------- /_testing/test.0030/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var F1 int 3 | var F2 int 4 | var F3 int 5 | -------------------------------------------------------------------------------- /_testing/test.0030/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type A struct { 4 | F1, F2, F3 int 5 | } 6 | 7 | type B A 8 | 9 | func main() { 10 | var b B 11 | b. 12 | } 13 | -------------------------------------------------------------------------------- /_testing/test.0031/cursor.80: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0031/cursor.80 -------------------------------------------------------------------------------- /_testing/test.0031/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func main() 3 | var c int 4 | -------------------------------------------------------------------------------- /_testing/test.0031/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var c chan int 5 | select { 6 | case c := <-c: 7 | _ = c 8 | 9 | default: 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /_testing/test.0032/cursor.1835: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0032/cursor.1835 -------------------------------------------------------------------------------- /_testing/test.0032/out.expected: -------------------------------------------------------------------------------- 1 | Found 124 candidates: 2 | func main() 3 | package adler32 4 | package aes 5 | package ascii85 6 | package asn1 7 | package ast 8 | package atomic 9 | package base32 10 | package base64 11 | package big 12 | package binary 13 | package bufio 14 | package build 15 | package bytes 16 | package bzip2 17 | package cgi 18 | package cgo 19 | package cipher 20 | package cmplx 21 | package color 22 | package crc32 23 | package crc64 24 | package crypto 25 | package csv 26 | package debug 27 | package des 28 | package doc 29 | package draw 30 | package driver 31 | package dsa 32 | package dwarf 33 | package ecdsa 34 | package elf 35 | package elliptic 36 | package errors 37 | package exec 38 | package expvar 39 | package fcgi 40 | package filepath 41 | package flag 42 | package flate 43 | package fmt 44 | package fnv 45 | package gif 46 | package gob 47 | package gosym 48 | package gzip 49 | package hash 50 | package heap 51 | package hex 52 | package hmac 53 | package html 54 | package http 55 | package httptest 56 | package httputil 57 | package image 58 | package io 59 | package iotest 60 | package ioutil 61 | package jpeg 62 | package json 63 | package jsonrpc 64 | package list 65 | package log 66 | package lzw 67 | package macho 68 | package mail 69 | package math 70 | package md5 71 | package mime 72 | package multipart 73 | package net 74 | package os 75 | package parse 76 | package parser 77 | package path 78 | package pe 79 | package pem 80 | package pkix 81 | package png 82 | package pprof 83 | package printer 84 | package quick 85 | package rand 86 | package rc4 87 | package reflect 88 | package regexp 89 | package ring 90 | package rpc 91 | package rsa 92 | package runtime 93 | package scanner 94 | package sha1 95 | package sha256 96 | package sha512 97 | package signal 98 | package smtp 99 | package sort 100 | package sql 101 | package strconv 102 | package strings 103 | package subtle 104 | package suffixarray 105 | package sync 106 | package syntax 107 | package syscall 108 | package syslog 109 | package tabwriter 110 | package tar 111 | package template 112 | package testing 113 | package textproto 114 | package time 115 | package tls 116 | package token 117 | package unicode 118 | package url 119 | package user 120 | package utf16 121 | package utf8 122 | package x509 123 | package xml 124 | package zip 125 | package zlib 126 | -------------------------------------------------------------------------------- /_testing/test.0032/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/tar" 5 | "archive/zip" 6 | "bufio" 7 | "bytes" 8 | "compress/bzip2" 9 | "compress/flate" 10 | "compress/gzip" 11 | "compress/lzw" 12 | "compress/zlib" 13 | "container/heap" 14 | "container/list" 15 | "container/ring" 16 | "crypto" 17 | "crypto/aes" 18 | "crypto/cipher" 19 | "crypto/des" 20 | "crypto/dsa" 21 | "crypto/ecdsa" 22 | "crypto/elliptic" 23 | "crypto/hmac" 24 | "crypto/md5" 25 | "crypto/rand" 26 | "crypto/rc4" 27 | "crypto/rsa" 28 | "crypto/sha1" 29 | "crypto/sha256" 30 | "crypto/sha512" 31 | "crypto/subtle" 32 | "crypto/tls" 33 | "crypto/x509" 34 | "crypto/x509/pkix" 35 | "database/sql" 36 | "database/sql/driver" 37 | "debug/dwarf" 38 | "debug/elf" 39 | "debug/gosym" 40 | "debug/macho" 41 | "debug/pe" 42 | "encoding/ascii85" 43 | "encoding/asn1" 44 | "encoding/base32" 45 | "encoding/base64" 46 | "encoding/binary" 47 | "encoding/csv" 48 | "encoding/gob" 49 | "encoding/hex" 50 | "encoding/json" 51 | "encoding/pem" 52 | "encoding/xml" 53 | "errors" 54 | "expvar" 55 | "flag" 56 | "fmt" 57 | "go/ast" 58 | "go/build" 59 | "go/doc" 60 | "go/parser" 61 | "go/printer" 62 | "go/scanner" 63 | "go/token" 64 | "hash" 65 | "hash/adler32" 66 | "hash/crc32" 67 | "hash/crc64" 68 | "hash/fnv" 69 | "html" 70 | "html/template" 71 | "image" 72 | "image/color" 73 | "image/draw" 74 | "image/gif" 75 | "image/jpeg" 76 | "image/png" 77 | "index/suffixarray" 78 | "io" 79 | "io/ioutil" 80 | "log" 81 | "log/syslog" 82 | "math" 83 | "math/big" 84 | "math/cmplx" 85 | "math/rand" 86 | "mime" 87 | "mime/multipart" 88 | "net" 89 | "net/http" 90 | "net/http/cgi" 91 | "net/http/fcgi" 92 | "net/http/httptest" 93 | "net/http/httputil" 94 | "net/http/pprof" 95 | "net/mail" 96 | "net/rpc" 97 | "net/rpc/jsonrpc" 98 | "net/smtp" 99 | "net/textproto" 100 | "net/url" 101 | "os" 102 | "os/exec" 103 | "os/signal" 104 | "os/user" 105 | "path" 106 | "path/filepath" 107 | "reflect" 108 | "regexp" 109 | "regexp/syntax" 110 | "runtime" 111 | "runtime/cgo" 112 | "runtime/debug" 113 | "runtime/pprof" 114 | "sort" 115 | "strconv" 116 | "strings" 117 | "sync" 118 | "sync/atomic" 119 | "syscall" 120 | "testing" 121 | "testing/iotest" 122 | "testing/quick" 123 | "text/scanner" 124 | "text/tabwriter" 125 | "text/template" 126 | "text/template/parse" 127 | "time" 128 | "unicode" 129 | "unicode/utf16" 130 | "unicode/utf8" 131 | ) 132 | 133 | func main() { 134 | 135 | } 136 | -------------------------------------------------------------------------------- /_testing/test.0033/cursor.138: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0033/cursor.138 -------------------------------------------------------------------------------- /_testing/test.0033/out.expected: -------------------------------------------------------------------------------- 1 | Found 6 candidates: 2 | func testEllipsis(dummies ...*Dummy) 3 | type Dummy struct 4 | var d *Dummy 5 | var dummies ...*Dummy 6 | var i int 7 | var x *Dummy 8 | -------------------------------------------------------------------------------- /_testing/test.0033/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Dummy struct { 4 | a, b, c int 5 | } 6 | 7 | func testEllipsis(dummies ...*Dummy) { 8 | for i, d := range dummies { 9 | x := dummies[0] 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /_testing/test.0034/cursor.82: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0034/cursor.82 -------------------------------------------------------------------------------- /_testing/test.0034/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | func At(x int, y int) color.Color 3 | func Bounds() image.Rectangle 4 | func ColorModel() color.Model 5 | -------------------------------------------------------------------------------- /_testing/test.0034/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "image/png" 4 | 5 | func test() { 6 | img, err := png.Decode(nil) 7 | img. 8 | } 9 | -------------------------------------------------------------------------------- /_testing/test.0035/cursor.91: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0035/cursor.91 -------------------------------------------------------------------------------- /_testing/test.0035/out.expected: -------------------------------------------------------------------------------- 1 | Found 5 candidates: 2 | func main() 3 | var err error 4 | var offset int 5 | var r rune 6 | var s string 7 | -------------------------------------------------------------------------------- /_testing/test.0035/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var err error 5 | s := err.Error() 6 | for offset, r := range s { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /_testing/test.0036/cursor.67: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0036/cursor.67 -------------------------------------------------------------------------------- /_testing/test.0036/out.expected: -------------------------------------------------------------------------------- 1 | Found 21 candidates: 2 | func Close() error 3 | func DWARF() (*dwarf.Data, error) 4 | func DynString(tag elf.DynTag) ([]string, error) 5 | func DynamicSymbols() ([]elf.Symbol, error) 6 | func ImportedLibraries() ([]string, error) 7 | func ImportedSymbols() ([]elf.ImportedSymbol, error) 8 | func Section(name string) *elf.Section 9 | func SectionByType(typ elf.SectionType) *elf.Section 10 | func Symbols() ([]elf.Symbol, error) 11 | var ABIVersion uint8 12 | var ByteOrder binary.ByteOrder 13 | var Class elf.Class 14 | var Data elf.Data 15 | var Entry uint64 16 | var FileHeader elf.FileHeader 17 | var Machine elf.Machine 18 | var OSABI elf.OSABI 19 | var Progs []*elf.Prog 20 | var Sections []*elf.Section 21 | var Type elf.Type 22 | var Version elf.Version 23 | -------------------------------------------------------------------------------- /_testing/test.0036/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "debug/elf" 4 | 5 | func main() { 6 | var f elf.File 7 | f. 8 | } -------------------------------------------------------------------------------- /_testing/test.0037/cursor.139: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0037/cursor.139 -------------------------------------------------------------------------------- /_testing/test.0037/out.expected: -------------------------------------------------------------------------------- 1 | Found 7 candidates: 2 | func main() 3 | type Array [5]int 4 | var a Array 5 | var s []string 6 | var s1 []string 7 | var s2 []int 8 | var s3 9 | -------------------------------------------------------------------------------- /_testing/test.0037/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Array [5]int 4 | 5 | func main() { 6 | var s []string 7 | var a Array 8 | s1 := append(s[:], "123") 9 | s2 := a[0:100500] 10 | s3 := append() 11 | 12 | } 13 | -------------------------------------------------------------------------------- /_testing/test.0038/cursor.87: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0038/cursor.87 -------------------------------------------------------------------------------- /_testing/test.0038/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func main() 3 | var x 4 | -------------------------------------------------------------------------------- /_testing/test.0038/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | if y := 20; y == 0 { 5 | } 6 | if x := 10; x == 0 { 7 | } else if 8 | } 9 | -------------------------------------------------------------------------------- /_testing/test.0039/cursor.88: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0039/cursor.88 -------------------------------------------------------------------------------- /_testing/test.0039/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func main() 3 | var z 4 | -------------------------------------------------------------------------------- /_testing/test.0039/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | z := 5 5 | if y := 20; y == 0 { 6 | } 7 | if x := 10; x == 0 { 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /_testing/test.0040/cursor.96: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0040/cursor.96 -------------------------------------------------------------------------------- /_testing/test.0040/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | func create_foo() Foo 3 | type Foo struct 4 | var t Foo 5 | -------------------------------------------------------------------------------- /_testing/test.0040/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Foo struct {} 4 | 5 | func (f *Foo) Bar() {} 6 | 7 | func create_foo() Foo { 8 | t := Foo{} 9 | 10 | } 11 | -------------------------------------------------------------------------------- /_testing/test.0041/cursor.140: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0041/cursor.140 -------------------------------------------------------------------------------- /_testing/test.0041/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var Xa int 3 | var Xb int 4 | var Xy Y 5 | -------------------------------------------------------------------------------- /_testing/test.0041/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type X struct { 4 | Xa int 5 | Xb int 6 | Xy Y 7 | } 8 | 9 | type Y struct { 10 | Ya int 11 | Yb int 12 | } 13 | 14 | func main() { 15 | x := X{ 16 | Xy: Y{ 17 | Ya: 1, 18 | }, 19 | 20 | } 21 | -------------------------------------------------------------------------------- /_testing/test.0042/cursor.126: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0042/cursor.126 -------------------------------------------------------------------------------- /_testing/test.0042/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | var Ya int 3 | var Yb int 4 | -------------------------------------------------------------------------------- /_testing/test.0042/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type X struct { 4 | Xa int 5 | Xb int 6 | Xy Y 7 | } 8 | 9 | type Y struct { 10 | Ya int 11 | Yb int 12 | } 13 | 14 | func main() { 15 | x := X{ 16 | Xy: Y{ 17 | 18 | } 19 | -------------------------------------------------------------------------------- /_testing/test.0043/cursor.182: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0043/cursor.182 -------------------------------------------------------------------------------- /_testing/test.0043/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | func foo() 3 | var Xa int 4 | var Xb int 5 | var Xy Y 6 | -------------------------------------------------------------------------------- /_testing/test.0043/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type X struct { 4 | Xa int 5 | Xb int 6 | Xy Y 7 | } 8 | 9 | type Y struct { 10 | Ya int 11 | Yb int 12 | } 13 | 14 | func (x X) foo() { 15 | return 16 | } 17 | 18 | func main() { 19 | x := X{ 20 | Xa: 1, 21 | Xb: 2, 22 | } 23 | y := Y{ 24 | Ya: x. 25 | } 26 | -------------------------------------------------------------------------------- /_testing/test.0044/cursor.105: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0044/cursor.105 -------------------------------------------------------------------------------- /_testing/test.0044/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | var Xa int 3 | var Xb int 4 | -------------------------------------------------------------------------------- /_testing/test.0044/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type X struct { 4 | Xa int 5 | Xb int 6 | } 7 | 8 | func (x X) foo() { 9 | return 10 | } 11 | 12 | func main() { 13 | x := X{ 14 | 15 | } 16 | -------------------------------------------------------------------------------- /_testing/test.0045/cursor.51: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0045/cursor.51 -------------------------------------------------------------------------------- /_testing/test.0045/out.expected: -------------------------------------------------------------------------------- 1 | Found 25 candidates: 2 | func Errorf(format string, a ...interface{}) error 3 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) 4 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 5 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 6 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) 7 | func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 8 | func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 9 | func Print(a ...interface{}) (n int, err error) 10 | func Printf(format string, a ...interface{}) (n int, err error) 11 | func Println(a ...interface{}) (n int, err error) 12 | func Scan(a ...interface{}) (n int, err error) 13 | func Scanf(format string, a ...interface{}) (n int, err error) 14 | func Scanln(a ...interface{}) (n int, err error) 15 | func Sprint(a ...interface{}) string 16 | func Sprintf(format string, a ...interface{}) string 17 | func Sprintln(a ...interface{}) string 18 | func Sscan(str string, a ...interface{}) (n int, err error) 19 | func Sscanf(str string, format string, a ...interface{}) (n int, err error) 20 | func Sscanln(str string, a ...interface{}) (n int, err error) 21 | type Formatter interface 22 | type GoStringer interface 23 | type ScanState interface 24 | type Scanner interface 25 | type State interface 26 | type Stringer interface 27 | -------------------------------------------------------------------------------- /_testing/test.0045/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | if fmt. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0046/cursor.53: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0046/cursor.53 -------------------------------------------------------------------------------- /_testing/test.0046/out.expected: -------------------------------------------------------------------------------- 1 | Found 25 candidates: 2 | func Errorf(format string, a ...interface{}) error 3 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) 4 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 5 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 6 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) 7 | func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 8 | func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 9 | func Print(a ...interface{}) (n int, err error) 10 | func Printf(format string, a ...interface{}) (n int, err error) 11 | func Println(a ...interface{}) (n int, err error) 12 | func Scan(a ...interface{}) (n int, err error) 13 | func Scanf(format string, a ...interface{}) (n int, err error) 14 | func Scanln(a ...interface{}) (n int, err error) 15 | func Sprint(a ...interface{}) string 16 | func Sprintf(format string, a ...interface{}) string 17 | func Sprintln(a ...interface{}) string 18 | func Sscan(str string, a ...interface{}) (n int, err error) 19 | func Sscanf(str string, format string, a ...interface{}) (n int, err error) 20 | func Sscanln(str string, a ...interface{}) (n int, err error) 21 | type Formatter interface 22 | type GoStringer interface 23 | type ScanState interface 24 | type Scanner interface 25 | type State interface 26 | type Stringer interface 27 | -------------------------------------------------------------------------------- /_testing/test.0046/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | x := fmt. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0047/cursor.43: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /_testing/test.0047/out.expected: -------------------------------------------------------------------------------- 1 | Nothing to complete. 2 | -------------------------------------------------------------------------------- /_testing/test.0047/test.go.in: -------------------------------------------------------------------------------- 1 | package p 2 | 3 | type T struct{ X } 4 | 5 | var _ = T.x. 6 | -------------------------------------------------------------------------------- /_testing/test.0048/cursor.53: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0048/cursor.53 -------------------------------------------------------------------------------- /_testing/test.0048/out.expected: -------------------------------------------------------------------------------- 1 | Found 7 candidates: 2 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) 3 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 4 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 5 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) 6 | func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 7 | func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 8 | type Formatter interface 9 | -------------------------------------------------------------------------------- /_testing/test.0048/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | x := fmt.Fpr 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0049/cursor.44: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0049/cursor.44 -------------------------------------------------------------------------------- /_testing/test.0049/out.expected: -------------------------------------------------------------------------------- 1 | Found 1 candidates: 2 | var i int 3 | -------------------------------------------------------------------------------- /_testing/test.0049/test.go.in: -------------------------------------------------------------------------------- 1 | package p 2 | 3 | func t(a struct { 4 | i int 5 | }) { 6 | a. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0050/cursor.45: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0050/cursor.45 -------------------------------------------------------------------------------- /_testing/test.0050/out.expected: -------------------------------------------------------------------------------- 1 | Found 1 candidates: 2 | var i int 3 | -------------------------------------------------------------------------------- /_testing/test.0050/test.go.in: -------------------------------------------------------------------------------- 1 | package p 2 | 3 | func t(a *struct { 4 | i int 5 | }) { 6 | a. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0051/cursor.247: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0051/cursor.247 -------------------------------------------------------------------------------- /_testing/test.0051/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var NumApples int 3 | var NumBananas int 4 | var NumOranges int 5 | -------------------------------------------------------------------------------- /_testing/test.0051/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Item struct { 4 | Quantity int 5 | Name string 6 | } 7 | 8 | type Config struct { 9 | NumApples int 10 | NumOranges int 11 | NumBananas int 12 | } 13 | 14 | func main() { 15 | var cfg Config 16 | items := []Item{ 17 | {cfg.NumApples, "apple"}, 18 | {cfg.NumOranges, "orange"}, 19 | {cfg.NumApples, "banana"}, 20 | } 21 | 22 | var a int 23 | var b int 24 | var c int 25 | var d int 26 | var e int 27 | var f int 28 | var g int 29 | var h int 30 | var i int 31 | var j int 32 | } 33 | -------------------------------------------------------------------------------- /_testing/test.0052/cursor.96: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0052/cursor.96 -------------------------------------------------------------------------------- /_testing/test.0052/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var A int 3 | var B int 4 | var C float64 5 | -------------------------------------------------------------------------------- /_testing/test.0052/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type FooBar struct { 4 | A int 5 | B int 6 | C float64 7 | } 8 | 9 | func main() { 10 | x := []FooBar{ 11 | {}, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /_testing/test.0053/cursor.215: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0053/cursor.215 -------------------------------------------------------------------------------- /_testing/test.0053/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | func Fooer() string 3 | var A int 4 | var B int 5 | var C float64 6 | -------------------------------------------------------------------------------- /_testing/test.0053/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type FooBar struct { 4 | A int 5 | B int 6 | C float64 7 | } 8 | 9 | func (b *FooBar) Foobarer() string { return "foobarer" } 10 | 11 | type Bar FooBar 12 | 13 | func (b *Bar) Fooer() string { return "fooer" } 14 | 15 | func main() { 16 | var b Bar 17 | b. 18 | } 19 | -------------------------------------------------------------------------------- /_testing/test.0054/cursor.168: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0054/cursor.168 -------------------------------------------------------------------------------- /_testing/test.0054/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | func Foobarer() string 3 | var A int 4 | var B int 5 | var C float64 6 | -------------------------------------------------------------------------------- /_testing/test.0054/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type FooBar struct { 4 | A int 5 | B int 6 | C float64 7 | } 8 | 9 | func (b *FooBar) Foobarer() string { return "foobarer" } 10 | 11 | type Bar = FooBar 12 | 13 | func main() { 14 | var b Bar 15 | b. 16 | } 17 | -------------------------------------------------------------------------------- /_testing/test.0055/cursor.229: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0055/cursor.229 -------------------------------------------------------------------------------- /_testing/test.0055/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var Jim string 3 | var John string 4 | var Kim string 5 | -------------------------------------------------------------------------------- /_testing/test.0055/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Baz struct { 4 | Jim string 5 | John string 6 | Kim string 7 | } 8 | 9 | type FooBar struct { 10 | A int 11 | B int 12 | C float64 13 | } 14 | 15 | func (b *FooBar) Foobarer() Baz { return Baz{} } 16 | 17 | func main() { 18 | type Bar = FooBar 19 | var b Bar 20 | b.Foobarer(). 21 | } 22 | -------------------------------------------------------------------------------- /_testing/test.0056/cursor.211: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0056/cursor.211 -------------------------------------------------------------------------------- /_testing/test.0056/out.expected: -------------------------------------------------------------------------------- 1 | Found 5 candidates: 2 | func MethodMe() bool 3 | func MethodYou() bool 4 | var A int 5 | var B int 6 | var C int 7 | -------------------------------------------------------------------------------- /_testing/test.0056/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func (x *Baz) MethodMe() bool { return true } 4 | 5 | func (x *Bar) MethodYou() bool { return false } 6 | 7 | type Foo struct { 8 | A int 9 | B int 10 | C int 11 | } 12 | 13 | type Bar = Foo 14 | type Baz = Bar 15 | 16 | func main() { 17 | var f Foo 18 | f. 19 | } 20 | -------------------------------------------------------------------------------- /_testing/test.0057/cursor.56: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0057/cursor.56 -------------------------------------------------------------------------------- /_testing/test.0057/out.expected: -------------------------------------------------------------------------------- 1 | Found 2 candidates: 2 | func Read(p []byte) (n int, err error) 3 | func Write(p []byte) (n int, err error) 4 | -------------------------------------------------------------------------------- /_testing/test.0057/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | func main() { 6 | io.ReadWriter. 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0058/cursor.65: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0058/cursor.65 -------------------------------------------------------------------------------- /_testing/test.0058/out.expected: -------------------------------------------------------------------------------- 1 | Found 1 candidates: 2 | func NewPackage(fset *token.FileSet, files map[string]*myast.File, importer myast.Importer, universe *myast.Scope) (*myast.Package, error) 3 | -------------------------------------------------------------------------------- /_testing/test.0058/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import myast "go/ast" 4 | 5 | func main() { 6 | myast.NewPack 7 | } 8 | -------------------------------------------------------------------------------- /_testing/test.0059/cursor.81: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0059/cursor.81 -------------------------------------------------------------------------------- /_testing/test.0059/out.expected: -------------------------------------------------------------------------------- 1 | Found 1 candidates: 2 | func NewReader(r io.Reader) io.Reader 3 | -------------------------------------------------------------------------------- /_testing/test.0059/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import myio "io" 4 | import "compress/bzip2" 5 | 6 | func main() { 7 | bzip2.NewR 8 | } 9 | -------------------------------------------------------------------------------- /_testing/test.0060/cursor.109: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0060/cursor.109 -------------------------------------------------------------------------------- /_testing/test.0060/out.expected: -------------------------------------------------------------------------------- 1 | Found 1 candidates: 2 | func Read(p []byte) (n int, err error) 3 | -------------------------------------------------------------------------------- /_testing/test.0060/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | func f() (a, b io.Reader, c error) { return a } 6 | 7 | func main() { 8 | a, b, c := f() 9 | b. 10 | } 11 | -------------------------------------------------------------------------------- /_testing/test.0061/cursor.61: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0061/cursor.61 -------------------------------------------------------------------------------- /_testing/test.0061/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | func Foo() *http.Request 3 | func main() 4 | package http 5 | -------------------------------------------------------------------------------- /_testing/test.0061/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net/http" 4 | 5 | func Foo() *http.Request { 6 | 7 | } 8 | 9 | func main() { 10 | } 11 | -------------------------------------------------------------------------------- /_testing/test.0062/cursor.141: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0062/cursor.141 -------------------------------------------------------------------------------- /_testing/test.0062/out.expected: -------------------------------------------------------------------------------- 1 | Found 4 candidates: 2 | var A int 3 | var ABCAlias ABCAlias 4 | var B int 5 | var C int 6 | -------------------------------------------------------------------------------- /_testing/test.0062/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type ABC struct { 4 | A int 5 | B int 6 | C int 7 | } 8 | 9 | type ABCAlias = ABC 10 | 11 | type Foo struct { 12 | ABCAlias 13 | } 14 | 15 | func main() { 16 | foo := Foo{} 17 | foo. 18 | } 19 | -------------------------------------------------------------------------------- /_testing/test.0063/cursor.109: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsf/gocode/b672b49f3818b1e1829babe10d5a25e560190d66/_testing/test.0063/cursor.109 -------------------------------------------------------------------------------- /_testing/test.0063/out.expected: -------------------------------------------------------------------------------- 1 | Found 3 candidates: 2 | var A int 3 | var B int 4 | var C int 5 | -------------------------------------------------------------------------------- /_testing/test.0063/test.go.in: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type ABC struct { 4 | A int 5 | B int 6 | C int 7 | } 8 | 9 | type ABCAlias = ABC 10 | 11 | func main() { 12 | x := ABCAlias{ 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "go/build" 7 | "io/ioutil" 8 | "net/rpc" 9 | "os" 10 | "path/filepath" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | func do_client() int { 16 | addr := *g_addr 17 | if *g_sock == "unix" { 18 | addr = get_socket_filename() 19 | } 20 | 21 | // client 22 | client, err := rpc.Dial(*g_sock, addr) 23 | if err != nil { 24 | if *g_sock == "unix" && file_exists(addr) { 25 | os.Remove(addr) 26 | } 27 | 28 | err = try_run_server() 29 | if err != nil { 30 | fmt.Printf("%s\n", err.Error()) 31 | return 1 32 | } 33 | client, err = try_to_connect(*g_sock, addr) 34 | if err != nil { 35 | fmt.Printf("%s\n", err.Error()) 36 | return 1 37 | } 38 | } 39 | defer client.Close() 40 | 41 | if flag.NArg() > 0 { 42 | switch flag.Arg(0) { 43 | case "autocomplete": 44 | cmd_auto_complete(client) 45 | case "close": 46 | cmd_close(client) 47 | case "status": 48 | cmd_status(client) 49 | case "drop-cache": 50 | cmd_drop_cache(client) 51 | case "set": 52 | cmd_set(client) 53 | case "options": 54 | cmd_options(client) 55 | default: 56 | fmt.Printf("unknown argument: %q, try running \"gocode -h\"\n", flag.Arg(0)) 57 | return 1 58 | } 59 | } 60 | return 0 61 | } 62 | 63 | func try_run_server() error { 64 | path := get_executable_filename() 65 | args := []string{os.Args[0], "-s", "-sock", *g_sock, "-addr", *g_addr} 66 | cwd, _ := os.Getwd() 67 | 68 | var err error 69 | stdin, err := os.Open(os.DevNull) 70 | if err != nil { 71 | return err 72 | } 73 | stdout, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) 74 | if err != nil { 75 | return err 76 | } 77 | stderr, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | procattr := os.ProcAttr{Dir: cwd, Env: os.Environ(), Files: []*os.File{stdin, stdout, stderr}} 83 | p, err := os.StartProcess(path, args, &procattr) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | return p.Release() 89 | } 90 | 91 | func try_to_connect(network, address string) (client *rpc.Client, err error) { 92 | t := 0 93 | for { 94 | client, err = rpc.Dial(network, address) 95 | if err != nil && t < 1000 { 96 | time.Sleep(10 * time.Millisecond) 97 | t += 10 98 | continue 99 | } 100 | break 101 | } 102 | 103 | return 104 | } 105 | 106 | func prepare_file_filename_cursor() ([]byte, string, int) { 107 | var file []byte 108 | var err error 109 | 110 | if *g_input != "" { 111 | file, err = ioutil.ReadFile(*g_input) 112 | } else { 113 | file, err = ioutil.ReadAll(os.Stdin) 114 | } 115 | 116 | if err != nil { 117 | panic(err.Error()) 118 | } 119 | 120 | var skipped int 121 | file, skipped = filter_out_shebang(file) 122 | 123 | filename := *g_input 124 | cursor := -1 125 | 126 | offset := "" 127 | switch flag.NArg() { 128 | case 2: 129 | offset = flag.Arg(1) 130 | case 3: 131 | filename = flag.Arg(1) // Override default filename 132 | offset = flag.Arg(2) 133 | } 134 | 135 | if offset != "" { 136 | if offset[0] == 'c' || offset[0] == 'C' { 137 | cursor, _ = strconv.Atoi(offset[1:]) 138 | cursor = char_to_byte_offset(file, cursor) 139 | } else { 140 | cursor, _ = strconv.Atoi(offset) 141 | } 142 | } 143 | 144 | cursor -= skipped 145 | if filename != "" && !filepath.IsAbs(filename) { 146 | cwd, _ := os.Getwd() 147 | filename = filepath.Join(cwd, filename) 148 | } 149 | return file, filename, cursor 150 | } 151 | 152 | //------------------------------------------------------------------------- 153 | // commands 154 | //------------------------------------------------------------------------- 155 | 156 | func cmd_status(c *rpc.Client) { 157 | fmt.Printf("%s\n", client_status(c, 0)) 158 | } 159 | 160 | func cmd_auto_complete(c *rpc.Client) { 161 | context := pack_build_context(&build.Default) 162 | file, filename, cursor := prepare_file_filename_cursor() 163 | f := get_formatter(*g_format) 164 | f.write_candidates(client_auto_complete(c, file, filename, cursor, context)) 165 | } 166 | 167 | func cmd_close(c *rpc.Client) { 168 | client_close(c, 0) 169 | } 170 | 171 | func cmd_drop_cache(c *rpc.Client) { 172 | client_drop_cache(c, 0) 173 | } 174 | 175 | func cmd_set(c *rpc.Client) { 176 | switch flag.NArg() { 177 | case 1: 178 | fmt.Print(client_set(c, "\x00", "\x00")) 179 | case 2: 180 | fmt.Print(client_set(c, flag.Arg(1), "\x00")) 181 | case 3: 182 | fmt.Print(client_set(c, flag.Arg(1), flag.Arg(2))) 183 | } 184 | } 185 | 186 | func cmd_options(c *rpc.Client) { 187 | fmt.Print(client_options(c, 0)) 188 | } 189 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "os" 10 | "reflect" 11 | "regexp" 12 | "strconv" 13 | ) 14 | 15 | //------------------------------------------------------------------------- 16 | // config 17 | // 18 | // Structure represents persistent config storage of the gocode daemon. Usually 19 | // the config is located somewhere in ~/.config/gocode directory. 20 | //------------------------------------------------------------------------- 21 | 22 | type config struct { 23 | ProposeBuiltins bool `json:"propose-builtins"` 24 | LibPath string `json:"lib-path"` 25 | CustomPkgPrefix string `json:"custom-pkg-prefix"` 26 | CustomVendorDir string `json:"custom-vendor-dir"` 27 | Autobuild bool `json:"autobuild"` 28 | ForceDebugOutput string `json:"force-debug-output"` 29 | PackageLookupMode string `json:"package-lookup-mode"` 30 | CloseTimeout int `json:"close-timeout"` 31 | UnimportedPackages bool `json:"unimported-packages"` 32 | Partials bool `json:"partials"` 33 | IgnoreCase bool `json:"ignore-case"` 34 | ClassFiltering bool `json:"class-filtering"` 35 | } 36 | 37 | var g_config_desc = map[string]string{ 38 | "propose-builtins": "If set to {true}, gocode will add built-in types, functions and constants to autocompletion proposals.", 39 | "lib-path": "A string option. Allows you to add search paths for packages. By default, gocode only searches {$GOPATH/pkg/$GOOS_$GOARCH} and {$GOROOT/pkg/$GOOS_$GOARCH} in terms of previously existed environment variables. Also you can specify multiple paths using ':' (colon) as a separator (on Windows use semicolon ';'). The paths specified by {lib-path} are prepended to the default ones.", 40 | "custom-pkg-prefix": "", 41 | "custom-vendor-dir": "", 42 | "autobuild": "If set to {true}, gocode will try to automatically build out-of-date packages when their source files are modified, in order to obtain the freshest autocomplete results for them. This feature is experimental.", 43 | "force-debug-output": "If is not empty, gocode will forcefully redirect the logging into that file. Also forces enabling of the debug mode on the server side.", 44 | "package-lookup-mode": "If set to {go}, use standard Go package lookup rules. If set to {gb}, use gb-specific lookup rules. See {https://github.com/constabulary/gb} for details.", 45 | "close-timeout": "If there have been no completion requests after this number of seconds, the gocode process will terminate. Default is 30 minutes.", 46 | "unimported-packages": "If set to {true}, gocode will try to import certain known packages automatically for identifiers which cannot be resolved otherwise. Currently only a limited set of standard library packages is supported.", 47 | "partials": "If set to {false}, gocode will not filter autocompletion results based on entered prefix before the cursor. Instead it will return all available autocompletion results viable for a given context. Whether this option is set to {true} or {false}, gocode will return a valid prefix length for output formats which support it. Setting this option to a non-default value may result in editor misbehaviour.", 48 | "ignore-case": "If set to {true}, gocode will perform case-insensitive matching when doing prefix-based filtering.", 49 | "class-filtering": "Enables or disables gocode's feature where it performs class-based filtering if partial input matches corresponding class keyword: const, var, type, func, package.", 50 | } 51 | 52 | var g_default_config = config{ 53 | ProposeBuiltins: false, 54 | LibPath: "", 55 | CustomPkgPrefix: "", 56 | Autobuild: false, 57 | ForceDebugOutput: "", 58 | PackageLookupMode: "go", 59 | CloseTimeout: 1800, 60 | UnimportedPackages: false, 61 | Partials: true, 62 | IgnoreCase: false, 63 | ClassFiltering: true, 64 | } 65 | var g_config = g_default_config 66 | 67 | var g_string_to_bool = map[string]bool{ 68 | "t": true, 69 | "true": true, 70 | "y": true, 71 | "yes": true, 72 | "on": true, 73 | "1": true, 74 | "f": false, 75 | "false": false, 76 | "n": false, 77 | "no": false, 78 | "off": false, 79 | "0": false, 80 | } 81 | 82 | func set_value(v reflect.Value, value string) { 83 | switch t := v; t.Kind() { 84 | case reflect.Bool: 85 | v, ok := g_string_to_bool[value] 86 | if ok { 87 | t.SetBool(v) 88 | } 89 | case reflect.String: 90 | t.SetString(value) 91 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 92 | v, err := strconv.ParseInt(value, 10, 64) 93 | if err == nil { 94 | t.SetInt(v) 95 | } 96 | case reflect.Float32, reflect.Float64: 97 | v, err := strconv.ParseFloat(value, 64) 98 | if err == nil { 99 | t.SetFloat(v) 100 | } 101 | } 102 | } 103 | 104 | func list_value(v reflect.Value, name string, w io.Writer) { 105 | switch t := v; t.Kind() { 106 | case reflect.Bool: 107 | fmt.Fprintf(w, "%s %v\n", name, t.Bool()) 108 | case reflect.String: 109 | fmt.Fprintf(w, "%s \"%v\"\n", name, t.String()) 110 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 111 | fmt.Fprintf(w, "%s %v\n", name, t.Int()) 112 | case reflect.Float32, reflect.Float64: 113 | fmt.Fprintf(w, "%s %v\n", name, t.Float()) 114 | } 115 | } 116 | 117 | func (this *config) list() string { 118 | str, typ := this.value_and_type() 119 | buf := bytes.NewBuffer(make([]byte, 0, 256)) 120 | for i := 0; i < str.NumField(); i++ { 121 | v := str.Field(i) 122 | name := typ.Field(i).Tag.Get("json") 123 | list_value(v, name, buf) 124 | } 125 | return buf.String() 126 | } 127 | 128 | func (this *config) list_option(name string) string { 129 | str, typ := this.value_and_type() 130 | buf := bytes.NewBuffer(make([]byte, 0, 256)) 131 | for i := 0; i < str.NumField(); i++ { 132 | v := str.Field(i) 133 | nm := typ.Field(i).Tag.Get("json") 134 | if nm == name { 135 | list_value(v, name, buf) 136 | } 137 | } 138 | return buf.String() 139 | } 140 | 141 | func (this *config) set_option(name, value string) string { 142 | str, typ := this.value_and_type() 143 | buf := bytes.NewBuffer(make([]byte, 0, 256)) 144 | for i := 0; i < str.NumField(); i++ { 145 | v := str.Field(i) 146 | nm := typ.Field(i).Tag.Get("json") 147 | if nm == name { 148 | set_value(v, value) 149 | list_value(v, name, buf) 150 | } 151 | } 152 | this.write() 153 | return buf.String() 154 | 155 | } 156 | 157 | func (this *config) value_and_type() (reflect.Value, reflect.Type) { 158 | v := reflect.ValueOf(this).Elem() 159 | return v, v.Type() 160 | } 161 | 162 | func (this *config) write() error { 163 | data, err := json.Marshal(this) 164 | if err != nil { 165 | return err 166 | } 167 | 168 | // make sure config dir exists 169 | dir := config_dir() 170 | if !file_exists(dir) { 171 | os.MkdirAll(dir, 0755) 172 | } 173 | 174 | f, err := os.Create(config_file()) 175 | if err != nil { 176 | return err 177 | } 178 | defer f.Close() 179 | 180 | _, err = f.Write(data) 181 | if err != nil { 182 | return err 183 | } 184 | 185 | return nil 186 | } 187 | 188 | func (this *config) read() error { 189 | data, err := ioutil.ReadFile(config_file()) 190 | if err != nil { 191 | return err 192 | } 193 | 194 | err = json.Unmarshal(data, this) 195 | if err != nil { 196 | return err 197 | } 198 | 199 | return nil 200 | } 201 | 202 | func quoted(v interface{}) string { 203 | switch v.(type) { 204 | case string: 205 | return fmt.Sprintf("%q", v) 206 | case int: 207 | return fmt.Sprint(v) 208 | case bool: 209 | return fmt.Sprint(v) 210 | default: 211 | panic("unreachable") 212 | } 213 | } 214 | 215 | var descRE = regexp.MustCompile(`{[^}]+}`) 216 | 217 | func preprocess_desc(v string) string { 218 | return descRE.ReplaceAllStringFunc(v, func(v string) string { 219 | return color_cyan + v[1:len(v)-1] + color_none 220 | }) 221 | } 222 | 223 | func (this *config) options() string { 224 | var buf bytes.Buffer 225 | fmt.Fprintf(&buf, "%sConfig file location%s: %s\n", color_white_bold, color_none, config_file()) 226 | dv := reflect.ValueOf(g_default_config) 227 | v, t := this.value_and_type() 228 | for i, n := 0, t.NumField(); i < n; i++ { 229 | f := t.Field(i) 230 | index := f.Index 231 | tag := f.Tag.Get("json") 232 | fmt.Fprintf(&buf, "\n%s%s%s\n", color_yellow_bold, tag, color_none) 233 | fmt.Fprintf(&buf, "%stype%s: %s\n", color_yellow, color_none, f.Type) 234 | fmt.Fprintf(&buf, "%svalue%s: %s\n", color_yellow, color_none, quoted(v.FieldByIndex(index).Interface())) 235 | fmt.Fprintf(&buf, "%sdefault%s: %s\n", color_yellow, color_none, quoted(dv.FieldByIndex(index).Interface())) 236 | fmt.Fprintf(&buf, "%sdescription%s: %s\n", color_yellow, color_none, preprocess_desc(g_config_desc[tag])) 237 | } 238 | 239 | return buf.String() 240 | } 241 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | gocode (0.0.1~20110805-1) oneiric; urgency=low 2 | 3 | * Initial release 4 | 5 | -- Juan L. Negron Fri, 05 Aug 2011 22:58:48 -0700 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: gocode 2 | Section: devel 3 | Priority: extra 4 | Maintainer: Juan L. Negron 5 | Build-Depends: debhelper (>= 7.0.50~), golang 6 | Standards-Version: 3.9.1 7 | Homepage: https://github.com/nsf/gocode 8 | #Vcs-Git: git://git.debian.org/collab-maint/gocode.git 9 | #Vcs-Browser: http://git.debian.org/?p=collab-maint/gocode.git;a=summary 10 | 11 | Package: gocode 12 | Architecture: any 13 | Depends: ${shlibs:Depends}, ${misc:Depends}, golang 14 | Description: An autocompletion daemon for the Go programming language 15 | Gocode is a helper tool which is intended to be integraded with your source 16 | code editor, like vim and emacs. It provides several advanced capabilities, 17 | which currently includes: 18 | - Context-sensitive autocompletion 19 | It is called daemon, because it uses client/server architecture for caching 20 | purposes. In particular, it makes autocompletions very fast. Typical 21 | autocompletion time with warm cache is 30ms, which is barely noticeable. 22 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This work was packaged for Ubuntu by: 2 | 3 | Juan L. Negron on Fri, 05 Aug 2011 22:58:48 -0700 4 | 5 | It was downloaded from: 6 | 7 | https://github.com/nsf/gocode 8 | 9 | Upstream Author(s) and copyright: 10 | 11 | Copyright (C) 2010 nsf 12 | 13 | License: 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | THE SOFTWARE. 32 | 33 | The Debian packaging is: 34 | 35 | Copyright (C) 2011 Canonical Ltd. 36 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/gocode.default: -------------------------------------------------------------------------------- 1 | # Defaults for gocode initscript 2 | # sourced by /etc/init.d/gocode 3 | # installed at /etc/default/gocode by the maintainer scripts 4 | 5 | # 6 | # This is a POSIX shell fragment 7 | # 8 | 9 | # Additional options that are passed to the Daemon. 10 | DAEMON_OPTS="" 11 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | export GOROOT=/usr/lib/go 12 | 13 | %: 14 | dh $@ 15 | 16 | override_dh_auto_install: install 17 | 18 | install: 19 | mkdir -p debian/gocode/usr/bin 20 | cp gocode debian/gocode/usr/bin 21 | mkdir -p debian/gocode/usr/share/gocode 22 | cp -av emacs debian/gocode/usr/share/gocode 23 | cp -av vim debian/gocode/usr/share/gocode 24 | mkdir -p debian/gocode/usr/share/doc/gocode 25 | cp LICENSE debian/gocode/usr/share/doc/gocode 26 | cp README.md debian/gocode/usr/share/doc/gocode 27 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /docs/IDE_integration.md: -------------------------------------------------------------------------------- 1 | 2 | # IDE Integration Guide # 3 | 4 | This guide should help programmers to develop Go lang plugins for IDEs and editors. It documents command arguments and output formats, and also mentions common pitfails. Note that gocode is not intended to be used from command-line by human. 5 | 6 | ## Code Completion Assistance ## 7 | 8 | Gocode proposes completion depending on current scope and context. Currently some obvious features are missed: 9 | * No keywords completion (no context-sensitive neither absolute) 10 | * No package names completion 11 | * No completion proposal priority 12 | * Information about context not passed to output, i.e. gocode does not report if you've typed `st.` or `fn(` 13 | 14 | Also keep in mind following things: 15 | * Editor keeps unsaved file copy in memory, so you should pass file content via stdin, or mirror it to temporary file and use `-in=*` parameter. Gocode does not support more than one unsaved file. 16 | * You should also pass full path (relative or absolute) to target file as parameter, otherwise completion will be incomplete because other files from the same package will not be resolved. 17 | * If coder started to type identifier like `Pr`, gocode will produce completions `Printf`, `Produce`, etc. In other words, completion contains identifier prefix and is already filtered. Filtering uses case-sensitive comparison if possible, and fallbacks to case-insensitive comparison. 18 | * If you want to see built-in identifiers like `uint32`, `error`, etc, you can call `gocode set propose-builtins yes` once. 19 | 20 | Use autocomplete command to produce completion assistance for particular position at file: 21 | ```bash 22 | # Read source from file and show completions for character at offset 449 from beginning 23 | gocode -f=json --in=server.go autocomplete 449 24 | # Read source from stdin (more suitable for editor since it keeps unsaved file copy in memory) 25 | gocode -f=json autocomplete 449 26 | # You can also pass target file path along with position, it's used to find other files from the same package 27 | gocode -f=json autocomplete server.go 889 28 | # By default gocode interprets offset as bytes offset, but 'c' or 'C' prefix means that offset is unicode code points offset 29 | gocode -f=json autocomplete server.go c619 30 | ``` 31 | 32 | ## Server-side Debug Mode ## 33 | 34 | There is a special server-side debug mode available in order to help developers with gocode integration. Invoke the gocode's server manually passing the following arguments: 35 | ```bash 36 | # make sure gocode server isn't running 37 | gocode close 38 | # -s for "server" 39 | # -debug for special server-side debug mode 40 | gocode -s -debug 41 | ``` 42 | 43 | After that when your editor sends autocompletion requests, the server will print some information about them to the stdout, for example: 44 | ``` 45 | Got autocompletion request for '/home/nsf/tmp/gobug/main.go' 46 | Cursor at: 52 47 | ------------------------------------------------------- 48 | package main 49 | 50 | import "bytes" 51 | 52 | func main() { 53 | bytes.F# 54 | } 55 | ------------------------------------------------------- 56 | Offset: 1 57 | Number of candidates found: 2 58 | Candidates are: 59 | func Fields(s []byte) [][]byte 60 | func FieldsFunc(s []byte, f func(rune) bool) [][]byte 61 | ======================================================= 62 | ``` 63 | 64 | Note that '#' symbol is inserted at the cursor location as gocode sees it. This debug mode is useful when you need to make sure your editor sends the right position in all cases. Keep in mind that Go source files are UTF-8 files, try inserting non-english comments before the completion location to check if everything works properly. 65 | 66 | [Output formats reference.](autocomplete_formats.md) 67 | -------------------------------------------------------------------------------- /docs/autocomplete_formats.md: -------------------------------------------------------------------------------- 1 | 2 | # Description of Completion Assistance Formats # 3 | 4 | Use `-f` parameter for `autocomplete` command to set format. "nice" format is the default and fallback. 5 | 6 | Following formats supported: 7 | * json 8 | * nice 9 | * vim 10 | * godit 11 | * emacs 12 | * csv 13 | 14 | ## json ### 15 | Generic JSON format. Example (manually formatted): 16 | ```json 17 | [6, [{ 18 | "class": "func", 19 | "name": "client_auto_complete", 20 | "type": "func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int)" 21 | }, { 22 | "class": "func", 23 | "name": "client_close", 24 | "type": "func(cli *rpc.Client, Arg0 int) int" 25 | }, { 26 | "class": "func", 27 | "name": "client_cursor_type_pkg", 28 | "type": "func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string)" 29 | }, { 30 | "class": "func", 31 | "name": "client_drop_cache", 32 | "type": "func(cli *rpc.Client, Arg0 int) int" 33 | }, { 34 | "class": "func", 35 | "name": "client_highlight", 36 | "type": "func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int)" 37 | }, { 38 | "class": "func", 39 | "name": "client_set", 40 | "type": "func(cli *rpc.Client, Arg0, Arg1 string) string" 41 | }, { 42 | "class": "func", 43 | "name": "client_status", 44 | "type": "func(cli *rpc.Client, Arg0 int) string" 45 | } 46 | ]] 47 | ``` 48 | Limitations: 49 | * `class` can be one of: `func`, `package`, `var`, `type`, `const`, `PANIC` 50 | * `PANIC` means suspicious error inside gocode 51 | * `name` is text which can be inserted 52 | * `type` can be used to create code assistance hint 53 | * You can re-format type by using following approach: if `class` is prefix of `type`, delete this prefix and add another prefix `class` + " " + `name`. 54 | 55 | ## nice ## 56 | You can use it to test from command-line. 57 | ``` 58 | Found 7 candidates: 59 | func client_auto_complete(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int) 60 | func client_close(cli *rpc.Client, Arg0 int) int 61 | func client_cursor_type_pkg(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string) 62 | func client_drop_cache(cli *rpc.Client, Arg0 int) int 63 | func client_highlight(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int) 64 | func client_set(cli *rpc.Client, Arg0, Arg1 string) string 65 | func client_status(cli *rpc.Client, Arg0 int) string 66 | ``` 67 | 68 | ## vim ## 69 | Format designed to be used in VIM scripts. Example: 70 | ``` 71 | [6, [{'word': 'client_auto_complete(', 'abbr': 'func client_auto_complete(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int)', 'info': 'func client_auto_complete(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int)'}, {'word': 'client_close(', 'abbr': 'func client_close(cli *rpc.Client, Arg0 int) int', 'info': 'func client_close(cli *rpc.Client, Arg0 int) int'}, {'word': 'client_cursor_type_pkg(', 'abbr': 'func client_cursor_type_pkg(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string)', 'info': 'func client_cursor_type_pkg(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string)'}, {'word': 'client_drop_cache(', 'abbr': 'func client_drop_cache(cli *rpc.Client, Arg0 int) int', 'info': 'func client_drop_cache(cli *rpc.Client, Arg0 int) int'}, {'word': 'client_highlight(', 'abbr': 'func client_highlight(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int)', 'info': 'func client_highlight(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int)'}, {'word': 'client_set(', 'abbr': 'func client_set(cli *rpc.Client, Arg0, Arg1 string) string', 'info': 'func client_set(cli *rpc.Client, Arg0, Arg1 string) string'}, {'word': 'client_status(', 'abbr': 'func client_status(cli *rpc.Client, Arg0 int) string', 'info': 'func client_status(cli *rpc.Client, Arg0 int) string'}]] 72 | ``` 73 | 74 | ## godit ## 75 | Example: 76 | ``` 77 | 6,,7 78 | func client_auto_complete(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int),,client_auto_complete( 79 | func client_close(cli *rpc.Client, Arg0 int) int,,client_close( 80 | func client_cursor_type_pkg(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string),,client_cursor_type_pkg( 81 | func client_drop_cache(cli *rpc.Client, Arg0 int) int,,client_drop_cache( 82 | func client_highlight(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int),,client_highlight( 83 | func client_set(cli *rpc.Client, Arg0, Arg1 string) string,,client_set( 84 | func client_status(cli *rpc.Client, Arg0 int) string,,client_status( 85 | ``` 86 | 87 | ## emacs ## 88 | Format designed to be used in Emacs scripts. Example: 89 | ``` 90 | client_auto_complete,,func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int) 91 | client_close,,func(cli *rpc.Client, Arg0 int) int 92 | client_cursor_type_pkg,,func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string) 93 | client_drop_cache,,func(cli *rpc.Client, Arg0 int) int 94 | client_highlight,,func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int) 95 | client_set,,func(cli *rpc.Client, Arg0, Arg1 string) string 96 | client_status,,func(cli *rpc.Client, Arg0 int) string 97 | ``` 98 | 99 | ## csv ## 100 | Comma-separated values format which has small size. Example: 101 | ```csv 102 | func,,client_auto_complete,,func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 gocode_env) (c []candidate, d int) 103 | func,,client_close,,func(cli *rpc.Client, Arg0 int) int 104 | func,,client_cursor_type_pkg,,func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int) (typ, pkg string) 105 | func,,client_drop_cache,,func(cli *rpc.Client, Arg0 int) int 106 | func,,client_highlight,,func(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 gocode_env) (c []highlight_range, d int) 107 | func,,client_set,,func(cli *rpc.Client, Arg0, Arg1 string) string 108 | func,,client_status,,func(cli *rpc.Client, Arg0 int) string 109 | ``` 110 | -------------------------------------------------------------------------------- /emacs-company/README.md: -------------------------------------------------------------------------------- 1 | # Company-go 2 | Company-go is an alternative emacs plugin for autocompletion. It uses [company-mode](http://company-mode.github.io). 3 | Completion will start automatically whenever the current symbol is preceded by a `.`, or after you type `company-minimum-prefix-length` letters. 4 | 5 | ## Setup 6 | Install `company` and `company-go`. 7 | 8 | Add the following to your emacs-config: 9 | 10 | ```lisp 11 | (require 'company) ; load company mode 12 | (require 'company-go) ; load company mode go backend 13 | ``` 14 | 15 | ## Possible improvements 16 | 17 | ```lisp 18 | (setq company-tooltip-limit 20) ; bigger popup window 19 | (setq company-idle-delay .3) ; decrease delay before autocompletion popup shows 20 | (setq company-echo-delay 0) ; remove annoying blinking 21 | (setq company-begin-commands '(self-insert-command)) ; start autocompletion only after typing 22 | ``` 23 | 24 | ### Only use company-mode with company-go in go-mode 25 | By default company-mode loads every backend it has. If you want to only have company-mode enabled in go-mode add the following to your emacs-config: 26 | 27 | ```lisp 28 | (add-hook 'go-mode-hook (lambda () 29 | (set (make-local-variable 'company-backends) '(company-go)) 30 | (company-mode))) 31 | ``` 32 | 33 | ### Color customization 34 | 35 | ```lisp 36 | (custom-set-faces 37 | '(company-preview 38 | ((t (:foreground "darkgray" :underline t)))) 39 | '(company-preview-common 40 | ((t (:inherit company-preview)))) 41 | '(company-tooltip 42 | ((t (:background "lightgray" :foreground "black")))) 43 | '(company-tooltip-selection 44 | ((t (:background "steelblue" :foreground "white")))) 45 | '(company-tooltip-common 46 | ((((type x)) (:inherit company-tooltip :weight bold)) 47 | (t (:inherit company-tooltip)))) 48 | '(company-tooltip-common-selection 49 | ((((type x)) (:inherit company-tooltip-selection :weight bold)) 50 | (t (:inherit company-tooltip-selection))))) 51 | ``` 52 | -------------------------------------------------------------------------------- /emacs/go-autocomplete.el: -------------------------------------------------------------------------------- 1 | ;;; go-autocomplete.el --- auto-complete-mode backend for go-mode 2 | 3 | ;; Copyright (C) 2010 4 | 5 | ;; Author: Mikhail Kuryshev 6 | ;; Keywords: languages 7 | ;; Package-Requires: ((auto-complete "1.4.0")) 8 | 9 | ;; This program is free software; you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | 14 | ;; This program is distributed in the hope that it will be useful, 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ;; GNU General Public License for more details. 18 | 19 | ;; You should have received a copy of the GNU General Public License 20 | ;; along with this program. If not, see . 21 | 22 | ;;; Commentary: 23 | 24 | ;; Ensure that go-autocomplete in your load-path and add to your ~/.emacs 25 | ;; following line: 26 | ;; 27 | ;; (require 'go-autocomplete) 28 | 29 | ;; Also you could setup any combination (for example M-TAB) 30 | ;; for invoking auto-complete: 31 | ;; 32 | ;; (require 'auto-complete-config) 33 | ;; (define-key ac-mode-map (kbd "M-TAB") 'auto-complete) 34 | 35 | ;;; Code: 36 | 37 | (eval-when-compile 38 | (require 'cl)) 39 | 40 | (require 'auto-complete) 41 | 42 | (declare-function yas-expand-snippet "yasnippet") 43 | 44 | (defgroup go-autocomplete nil 45 | "auto-complete for go language." 46 | :prefix "ac-go-" 47 | :group 'auto-complete) 48 | 49 | (defcustom ac-go-expand-arguments-into-snippets t 50 | "Expand function arguments into snippets. This feature requires `yasnippet'." 51 | :type 'boolean 52 | :group 'go-autocomplete) 53 | 54 | (defcustom ac-go-gocode-bin "gocode" 55 | "Overwrite path to gocode binary" 56 | :type 'string 57 | :group 'go-autocomplete) 58 | 59 | ;; Close gocode daemon at exit unless it was already running 60 | (eval-after-load "go-mode" 61 | '(progn 62 | (let* ((user (or (getenv "USER") "all")) 63 | (sock (format (concat temporary-file-directory "gocode-daemon.%s") user))) 64 | (unless (file-exists-p sock) 65 | (add-hook 'kill-emacs-hook #'(lambda () 66 | (ignore-errors 67 | (call-process "gocode" nil nil nil "close")))))))) 68 | 69 | ;(defvar go-reserved-keywords 70 | ; '("break" "case" "chan" "const" "continue" "default" "defer" "else" 71 | ; "fallthrough" "for" "func" "go" "goto" "if" "import" "interface" 72 | ; "map" "package" "range" "return" "select" "struct" "switch" "type" "var") 73 | ; "Go reserved keywords.") 74 | 75 | (defun ac-comphist-sort (db collection prefix &optional threshold) 76 | ;; redefine to disable sorting 77 | (let (result 78 | (n 0) 79 | (total 0) 80 | (cur 0)) 81 | (setq result (mapcar (lambda (a) 82 | (when (and cur threshold) 83 | (if (>= cur (* total threshold)) 84 | (setq cur nil) 85 | (incf n) 86 | (incf cur (cdr a)))) 87 | (car a)) 88 | (mapcar (lambda (string) 89 | (let ((score (ac-comphist-score db string prefix))) 90 | (incf total score) 91 | (cons string score))) 92 | collection))) 93 | (if threshold 94 | (cons n result) 95 | result))) 96 | 97 | (defun ac-go-invoke-autocomplete () 98 | (let ((temp-buffer (generate-new-buffer "*gocode*"))) 99 | (unwind-protect 100 | (progn 101 | (call-process-region (point-min) 102 | (point-max) 103 | ac-go-gocode-bin 104 | nil 105 | temp-buffer 106 | nil 107 | "-f=emacs" 108 | "autocomplete" 109 | (or (buffer-file-name) "") 110 | (concat "c" (int-to-string (- (point) 1)))) 111 | (with-current-buffer temp-buffer (buffer-string))) 112 | (kill-buffer temp-buffer)))) 113 | 114 | (defun ac-go-format-autocomplete (buffer-contents) 115 | (sort 116 | (split-string buffer-contents "\n" t) 117 | (lambda (a b) (string< (downcase a) 118 | (downcase b))))) 119 | 120 | (defun ac-go-get-candidates (strings) 121 | (let ((prop (lambda (entry) 122 | (let* ((name (nth 0 entry)) 123 | (summary (nth 1 entry)) 124 | (symbol (substring summary 0 1))) 125 | (propertize name 126 | 'summary summary 127 | 'symbol symbol)))) 128 | (split (lambda (strings) 129 | (mapcar (lambda (str) 130 | (split-string str ",," t)) 131 | strings)))) 132 | (mapcar prop (funcall split strings)))) 133 | 134 | (defun ac-go-action () 135 | (let ((item (cdr ac-last-completion))) 136 | (when (stringp item) 137 | (let ((symbol (get-text-property 0 'summary item))) 138 | (message "%s" symbol) 139 | (when (and (featurep 'yasnippet) ac-go-expand-arguments-into-snippets) 140 | (ac-go-insert-yas-snippet-string symbol)))))) 141 | 142 | (defun ac-go-insert-yas-snippet-string (s) 143 | (let ((ret "") (pos (point)) match-res match args) 144 | (save-match-data 145 | (setq match-res (string-match "func(." s)) 146 | (when (and match-res (= 0 match-res)) 147 | (setq match (match-string 0 s)) 148 | (unless (string= match "func()") 149 | (setq args (ac-go-split-args s)) 150 | (dolist (arg args) 151 | (setq ret (concat ret "${" arg "}, "))) 152 | (when (> (length ret) 2) 153 | (setq ret (substring ret 0 (- (length ret) 2))))) 154 | (setq ret (concat "(" ret ")")) 155 | (yas-expand-snippet ret pos pos))))) 156 | 157 | (defun ac-go-split-args (args-str) 158 | (let ((cur 5) 159 | (pre 5) 160 | (unmatch-l-paren-count 1) 161 | (args (list)) 162 | c) 163 | (while (> unmatch-l-paren-count 0) 164 | (setq c (aref args-str cur)) 165 | (cond ((= ?\( c) 166 | (setq unmatch-l-paren-count (1+ unmatch-l-paren-count))) 167 | ((= ?\) c) 168 | (setq unmatch-l-paren-count (1- unmatch-l-paren-count)) 169 | (when (= 0 unmatch-l-paren-count) 170 | (push (substring args-str pre cur) args))) 171 | ((= ?\, c) 172 | (when (= 1 unmatch-l-paren-count) 173 | (push (substring args-str pre cur) args) 174 | (setq cur (+ cur 2)) 175 | (setq pre cur)))) 176 | (setq cur (1+ cur))) 177 | (nreverse args))) 178 | 179 | (defun ac-go-document (item) 180 | (if (stringp item) 181 | (let ((s (get-text-property 0 'summary item))) 182 | (message "%s" s) 183 | nil))) 184 | 185 | (defun ac-go-candidates () 186 | (let ((candidates (ac-go-get-candidates 187 | (ac-go-format-autocomplete (ac-go-invoke-autocomplete))))) 188 | (if (equal candidates '("PANIC")) 189 | (progn 190 | (message "GOCODE PANIC: Please check your code by \"go build\"") 191 | nil) 192 | candidates))) 193 | 194 | (defun ac-go-prefix () 195 | (or (ac-prefix-symbol) 196 | (let ((c (char-before))) 197 | (when (eq ?\. c) 198 | (point))))) 199 | 200 | (ac-define-source go 201 | '((candidates . ac-go-candidates) 202 | (candidate-face . ac-candidate-face) 203 | (selection-face . ac-selection-face) 204 | (document . ac-go-document) 205 | (action . ac-go-action) 206 | (prefix . ac-go-prefix) 207 | (requires . 0) 208 | (cache))) 209 | 210 | (add-to-list 'ac-modes 'go-mode) 211 | 212 | (add-hook 'go-mode-hook #'(lambda () 213 | (add-to-list 'ac-sources 'ac-source-go))) 214 | 215 | (provide 'go-autocomplete) 216 | ;;; go-autocomplete.el ends here 217 | -------------------------------------------------------------------------------- /formatters.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | //------------------------------------------------------------------------- 9 | // formatter interfaces 10 | //------------------------------------------------------------------------- 11 | 12 | type formatter interface { 13 | write_candidates(candidates []candidate, num int) 14 | } 15 | 16 | //------------------------------------------------------------------------- 17 | // nice_formatter (just for testing, simple textual output) 18 | //------------------------------------------------------------------------- 19 | 20 | type nice_formatter struct{} 21 | 22 | func (*nice_formatter) write_candidates(candidates []candidate, num int) { 23 | if candidates == nil { 24 | fmt.Printf("Nothing to complete.\n") 25 | return 26 | } 27 | 28 | fmt.Printf("Found %d candidates:\n", len(candidates)) 29 | for _, c := range candidates { 30 | abbr := fmt.Sprintf("%s %s %s", c.Class, c.Name, c.Type) 31 | if c.Class == decl_func { 32 | abbr = fmt.Sprintf("%s %s%s", c.Class, c.Name, c.Type[len("func"):]) 33 | } 34 | fmt.Printf(" %s\n", abbr) 35 | } 36 | } 37 | 38 | //------------------------------------------------------------------------- 39 | // vim_formatter 40 | //------------------------------------------------------------------------- 41 | 42 | type vim_formatter struct{} 43 | 44 | func (*vim_formatter) write_candidates(candidates []candidate, num int) { 45 | if candidates == nil { 46 | fmt.Print("[0, []]") 47 | return 48 | } 49 | 50 | fmt.Printf("[%d, [", num) 51 | for i, c := range candidates { 52 | if i != 0 { 53 | fmt.Printf(", ") 54 | } 55 | 56 | word := c.Name 57 | if c.Class == decl_func { 58 | word += "(" 59 | if strings.HasPrefix(c.Type, "func()") { 60 | word += ")" 61 | } 62 | } 63 | 64 | abbr := fmt.Sprintf("%s %s %s", c.Class, c.Name, c.Type) 65 | if c.Class == decl_func { 66 | abbr = fmt.Sprintf("%s %s%s", c.Class, c.Name, c.Type[len("func"):]) 67 | } 68 | fmt.Printf("{'word': '%s', 'abbr': '%s', 'info': '%s'}", word, abbr, abbr) 69 | } 70 | fmt.Printf("]]") 71 | } 72 | 73 | //------------------------------------------------------------------------- 74 | // godit_formatter 75 | //------------------------------------------------------------------------- 76 | 77 | type godit_formatter struct{} 78 | 79 | func (*godit_formatter) write_candidates(candidates []candidate, num int) { 80 | fmt.Printf("%d,,%d\n", num, len(candidates)) 81 | for _, c := range candidates { 82 | contents := c.Name 83 | if c.Class == decl_func { 84 | contents += "(" 85 | if strings.HasPrefix(c.Type, "func()") { 86 | contents += ")" 87 | } 88 | } 89 | 90 | display := fmt.Sprintf("%s %s %s", c.Class, c.Name, c.Type) 91 | if c.Class == decl_func { 92 | display = fmt.Sprintf("%s %s%s", c.Class, c.Name, c.Type[len("func"):]) 93 | } 94 | fmt.Printf("%s,,%s\n", display, contents) 95 | } 96 | } 97 | 98 | //------------------------------------------------------------------------- 99 | // emacs_formatter 100 | //------------------------------------------------------------------------- 101 | 102 | type emacs_formatter struct{} 103 | 104 | func (*emacs_formatter) write_candidates(candidates []candidate, num int) { 105 | for _, c := range candidates { 106 | var hint string 107 | switch { 108 | case c.Class == decl_func: 109 | hint = c.Type 110 | case c.Type == "": 111 | hint = c.Class.String() 112 | default: 113 | hint = c.Class.String() + " " + c.Type 114 | } 115 | fmt.Printf("%s,,%s\n", c.Name, hint) 116 | } 117 | } 118 | 119 | //------------------------------------------------------------------------- 120 | // csv_formatter 121 | //------------------------------------------------------------------------- 122 | 123 | type csv_formatter struct{} 124 | 125 | func (*csv_formatter) write_candidates(candidates []candidate, num int) { 126 | for _, c := range candidates { 127 | fmt.Printf("%s,,%s,,%s\n", c.Class, c.Name, c.Type) 128 | } 129 | } 130 | 131 | //------------------------------------------------------------------------- 132 | // csv_with_package_formatter 133 | //------------------------------------------------------------------------- 134 | 135 | type csv_with_package_formatter struct{} 136 | 137 | func (*csv_with_package_formatter) write_candidates(candidates []candidate, num int) { 138 | for _, c := range candidates { 139 | fmt.Printf("%s,,%s,,%s,,%s\n", c.Class, c.Name, c.Type, c.Package) 140 | } 141 | } 142 | 143 | //------------------------------------------------------------------------- 144 | // json_formatter 145 | //------------------------------------------------------------------------- 146 | 147 | type json_formatter struct{} 148 | 149 | func (*json_formatter) write_candidates(candidates []candidate, num int) { 150 | if candidates == nil { 151 | fmt.Print("[]") 152 | return 153 | } 154 | 155 | fmt.Printf(`[%d, [`, num) 156 | for i, c := range candidates { 157 | if i != 0 { 158 | fmt.Printf(", ") 159 | } 160 | fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s", "package": "%s"}`, 161 | c.Class, c.Name, c.Type, c.Package) 162 | } 163 | fmt.Print("]]") 164 | } 165 | 166 | //------------------------------------------------------------------------- 167 | 168 | func get_formatter(name string) formatter { 169 | switch name { 170 | case "vim": 171 | return new(vim_formatter) 172 | case "emacs": 173 | return new(emacs_formatter) 174 | case "nice": 175 | return new(nice_formatter) 176 | case "csv": 177 | return new(csv_formatter) 178 | case "csv-with-package": 179 | return new(csv_with_package_formatter) 180 | case "json": 181 | return new(json_formatter) 182 | case "godit": 183 | return new(godit_formatter) 184 | } 185 | return new(nice_formatter) 186 | } 187 | -------------------------------------------------------------------------------- /gocode.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | _ "net/http/pprof" 9 | "os" 10 | "path/filepath" 11 | ) 12 | 13 | var ( 14 | g_is_server = flag.Bool("s", false, "run a server instead of a client") 15 | g_format = flag.String("f", "nice", "output format (vim | emacs | nice | csv | csv-with-package | json)") 16 | g_input = flag.String("in", "", "use this file instead of stdin input") 17 | g_sock = create_sock_flag("sock", "socket type (unix | tcp)") 18 | g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket") 19 | g_debug = flag.Bool("debug", false, "enable server-side debug mode") 20 | g_profile = flag.Int("profile", 0, "port on which to expose profiling information for pprof; 0 to disable profiling") 21 | ) 22 | 23 | func get_socket_filename() string { 24 | user := os.Getenv("USER") 25 | if user == "" { 26 | user = "all" 27 | } 28 | return filepath.Join(os.TempDir(), fmt.Sprintf("gocode-daemon.%s", user)) 29 | } 30 | 31 | func show_usage() { 32 | fmt.Fprintf(os.Stderr, 33 | "Usage: %s [-s] [-f=] [-in=] [-sock=] [-addr=]\n"+ 34 | " []\n\n", 35 | os.Args[0]) 36 | fmt.Fprintf(os.Stderr, 37 | "Flags:\n") 38 | flag.PrintDefaults() 39 | fmt.Fprintf(os.Stderr, 40 | "\nCommands:\n"+ 41 | " autocomplete [] main autocompletion command\n"+ 42 | " close close the gocode daemon\n"+ 43 | " drop-cache drop gocode daemon's cache\n"+ 44 | " options list config options (extended)\n"+ 45 | " set [ []] list or set config options\n"+ 46 | " status gocode daemon status report\n"+ 47 | "") 48 | } 49 | 50 | func main() { 51 | flag.Usage = show_usage 52 | flag.Parse() 53 | 54 | var retval int 55 | if *g_is_server { 56 | go func() { 57 | if *g_profile <= 0 { 58 | return 59 | } 60 | addr := fmt.Sprintf("localhost:%d", *g_profile) 61 | // Use the following commands to profile the binary: 62 | // go tool pprof http://localhost:6060/debug/pprof/profile # 30-second CPU profile 63 | // go tool pprof http://localhost:6060/debug/pprof/heap # heap profile 64 | // go tool pprof http://localhost:6060/debug/pprof/block # goroutine blocking profile 65 | // See http://blog.golang.org/profiling-go-programs for more info. 66 | log.Printf("enabling profiler on %s", addr) 67 | log.Print(http.ListenAndServe(addr, nil)) 68 | }() 69 | retval = do_server() 70 | } else { 71 | retval = do_client() 72 | } 73 | os.Exit(retval) 74 | } 75 | -------------------------------------------------------------------------------- /nvim/autoload/gocomplete.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_gocode') 2 | finish 3 | endif 4 | let g:loaded_gocode = 1 5 | 6 | fu! s:gocodeCurrentBuffer() 7 | let buf = getline(1, '$') 8 | if &encoding != 'utf-8' 9 | let buf = map(buf, 'iconv(v:val, &encoding, "utf-8")') 10 | endif 11 | if &l:fileformat == 'dos' 12 | " XXX: line2byte() depend on 'fileformat' option. 13 | " so if fileformat is 'dos', 'buf' must include '\r'. 14 | let buf = map(buf, 'v:val."\r"') 15 | endif 16 | let file = tempname() 17 | call writefile(buf, file) 18 | return file 19 | endf 20 | 21 | let s:vim_system = get(g:, 'gocomplete#system_function', 'system') 22 | 23 | fu! s:system(str, ...) 24 | return call(s:vim_system, [a:str] + a:000) 25 | endf 26 | 27 | fu! s:gocodeShellescape(arg) 28 | try 29 | let ssl_save = &shellslash 30 | set noshellslash 31 | return shellescape(a:arg) 32 | finally 33 | let &shellslash = ssl_save 34 | endtry 35 | endf 36 | 37 | fu! s:gocodeCommand(cmd, preargs, args) 38 | for i in range(0, len(a:args) - 1) 39 | let a:args[i] = s:gocodeShellescape(a:args[i]) 40 | endfor 41 | for i in range(0, len(a:preargs) - 1) 42 | let a:preargs[i] = s:gocodeShellescape(a:preargs[i]) 43 | endfor 44 | let result = s:system(printf('gocode %s %s %s', join(a:preargs), a:cmd, join(a:args))) 45 | if v:shell_error != 0 46 | return "[\"0\", []]" 47 | else 48 | if &encoding != 'utf-8' 49 | let result = iconv(result, 'utf-8', &encoding) 50 | endif 51 | return result 52 | endif 53 | endf 54 | 55 | fu! s:gocodeCurrentBufferOpt(filename) 56 | return '-in=' . a:filename 57 | endf 58 | 59 | fu! s:gocodeCursor() 60 | if &encoding != 'utf-8' 61 | let c = col('.') 62 | let buf = line('.') == 1 ? "" : (join(getline(1, line('.')-1), "\n") . "\n") 63 | let buf .= c == 1 ? "" : getline('.')[:c-2] 64 | return printf('%d', len(iconv(buf, &encoding, "utf-8"))) 65 | endif 66 | return printf('%d', line2byte(line('.')) + (col('.')-2)) 67 | endf 68 | 69 | fu! s:gocodeAutocomplete() 70 | let filename = s:gocodeCurrentBuffer() 71 | let result = s:gocodeCommand('autocomplete', 72 | \ [s:gocodeCurrentBufferOpt(filename), '-f=vim'], 73 | \ [expand('%:p'), s:gocodeCursor()]) 74 | call delete(filename) 75 | return result 76 | endf 77 | 78 | fu! gocomplete#Complete(findstart, base) 79 | "findstart = 1 when we need to get the text length 80 | if a:findstart == 1 81 | execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete() 82 | return col('.') - g:gocomplete_completions[0] - 1 83 | "findstart = 0 when we need to return the list of completions 84 | else 85 | return g:gocomplete_completions[1] 86 | endif 87 | endf 88 | -------------------------------------------------------------------------------- /nvim/ftplugin/go/gocomplete.vim: -------------------------------------------------------------------------------- 1 | setlocal omnifunc=gocomplete#Complete 2 | -------------------------------------------------------------------------------- /nvim/pathogen_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -z $XDG_CONFIG_HOME ]; then 3 | XDG_CONFIG_HOME="$HOME/.config" 4 | fi 5 | mkdir -p "$XDG_CONFIG_HOME/nvim/bundle/gocode/autoload" 6 | mkdir -p "$XDG_CONFIG_HOME/nvim/bundle/gocode/ftplugin/go" 7 | cp "${0%/*}/autoload/gocomplete.vim" "$XDG_CONFIG_HOME/nvim/bundle/gocode/autoload" 8 | cp "${0%/*}/ftplugin/go/gocomplete.vim" "$XDG_CONFIG_HOME/nvim/bundle/gocode/ftplugin/go" 9 | -------------------------------------------------------------------------------- /nvim/symlink.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd "${0%/*}" 3 | ROOTDIR=`pwd` 4 | mkdir -p "$HOME/.config/nvim/autoload" 5 | mkdir -p "$HOME/.config/nvim/ftplugin/go" 6 | ln -fs "$ROOTDIR/autoload/gocomplete.vim" "$HOME/.config/nvim/autoload/" 7 | ln -fs "$ROOTDIR/ftplugin/go/gocomplete.vim" "$HOME/.config/nvim/ftplugin/go/" 8 | -------------------------------------------------------------------------------- /nvim/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p "$HOME/.config/nvim/autoload" 3 | mkdir -p "$HOME/.config/nvim/ftplugin/go" 4 | cp "${0%/*}/autoload/gocomplete.vim" "$HOME/.config/nvim/autoload" 5 | cp "${0%/*}/ftplugin/go/gocomplete.vim" "$HOME/.config/nvim/ftplugin/go" 6 | -------------------------------------------------------------------------------- /os_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "os" 8 | "os/exec" 9 | "path/filepath" 10 | ) 11 | 12 | func create_sock_flag(name, desc string) *string { 13 | return flag.String(name, "unix", desc) 14 | } 15 | 16 | // Full path of the current executable 17 | func get_executable_filename() string { 18 | // try readlink first 19 | path, err := os.Readlink("/proc/self/exe") 20 | if err == nil { 21 | return path 22 | } 23 | // use argv[0] 24 | path = os.Args[0] 25 | if !filepath.IsAbs(path) { 26 | cwd, _ := os.Getwd() 27 | path = filepath.Join(cwd, path) 28 | } 29 | if file_exists(path) { 30 | return path 31 | } 32 | // Fallback : use "gocode" and assume we are in the PATH... 33 | path, err = exec.LookPath("gocode") 34 | if err == nil { 35 | return path 36 | } 37 | return "" 38 | } 39 | 40 | // config location 41 | 42 | func config_dir() string { 43 | return filepath.Join(xdg_home_dir(), "gocode") 44 | } 45 | 46 | func config_file() string { 47 | return filepath.Join(xdg_home_dir(), "gocode", "config.json") 48 | } 49 | -------------------------------------------------------------------------------- /os_windows.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "path/filepath" 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | var ( 12 | shell32 = syscall.NewLazyDLL("shell32.dll") 13 | kernel32 = syscall.NewLazyDLL("kernel32.dll") 14 | ) 15 | 16 | var ( 17 | proc_sh_get_folder_path = shell32.NewProc("SHGetFolderPathW") 18 | proc_get_module_file_name = kernel32.NewProc("GetModuleFileNameW") 19 | ) 20 | 21 | func create_sock_flag(name, desc string) *string { 22 | return flag.String(name, "tcp", desc) 23 | } 24 | 25 | // Full path of the current executable 26 | func get_executable_filename() string { 27 | b := make([]uint16, syscall.MAX_PATH) 28 | ret, _, err := syscall.Syscall(proc_get_module_file_name.Addr(), 3, 29 | 0, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))) 30 | if int(ret) == 0 { 31 | panic(fmt.Sprintf("GetModuleFileNameW : err %d", int(err))) 32 | } 33 | return syscall.UTF16ToString(b) 34 | } 35 | 36 | const ( 37 | csidl_appdata = 0x1a 38 | ) 39 | 40 | func get_appdata_folder_path() string { 41 | b := make([]uint16, syscall.MAX_PATH) 42 | ret, _, err := syscall.Syscall6(proc_sh_get_folder_path.Addr(), 5, 43 | 0, csidl_appdata, 0, 0, uintptr(unsafe.Pointer(&b[0])), 0) 44 | if int(ret) != 0 { 45 | panic(fmt.Sprintf("SHGetFolderPathW : err %d", int(err))) 46 | } 47 | return syscall.UTF16ToString(b) 48 | } 49 | 50 | func config_dir() string { 51 | return filepath.Join(get_appdata_folder_path(), "gocode") 52 | } 53 | 54 | func config_file() string { 55 | return filepath.Join(get_appdata_folder_path(), "gocode", "config.json") 56 | } 57 | -------------------------------------------------------------------------------- /package.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/ast" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | type package_parser interface { 12 | parse_export(callback func(pkg string, decl ast.Decl)) 13 | } 14 | 15 | //------------------------------------------------------------------------- 16 | // package_file_cache 17 | // 18 | // Structure that represents a cache for an imported pacakge. In other words 19 | // these are the contents of an archive (*.a) file. 20 | //------------------------------------------------------------------------- 21 | 22 | type package_file_cache struct { 23 | name string // file name 24 | import_name string 25 | mtime int64 26 | defalias string 27 | 28 | scope *scope 29 | main *decl // package declaration 30 | others map[string]*decl 31 | } 32 | 33 | func new_package_file_cache(absname, name string) *package_file_cache { 34 | m := new(package_file_cache) 35 | m.name = absname 36 | m.import_name = name 37 | m.mtime = 0 38 | m.defalias = "" 39 | return m 40 | } 41 | 42 | // Creates a cache that stays in cache forever. Useful for built-in packages. 43 | func new_package_file_cache_forever(name, defalias string) *package_file_cache { 44 | m := new(package_file_cache) 45 | m.name = name 46 | m.mtime = -1 47 | m.defalias = defalias 48 | return m 49 | } 50 | 51 | func (m *package_file_cache) find_file() string { 52 | if file_exists(m.name) { 53 | return m.name 54 | } 55 | 56 | n := len(m.name) 57 | filename := m.name[:n-1] + "6" 58 | if file_exists(filename) { 59 | return filename 60 | } 61 | 62 | filename = m.name[:n-1] + "8" 63 | if file_exists(filename) { 64 | return filename 65 | } 66 | 67 | filename = m.name[:n-1] + "5" 68 | if file_exists(filename) { 69 | return filename 70 | } 71 | return m.name 72 | } 73 | 74 | func (m *package_file_cache) update_cache() { 75 | if m.mtime == -1 { 76 | return 77 | } 78 | fname := m.find_file() 79 | stat, err := os.Stat(fname) 80 | if err != nil { 81 | return 82 | } 83 | 84 | statmtime := stat.ModTime().UnixNano() 85 | if m.mtime != statmtime { 86 | m.mtime = statmtime 87 | 88 | data, err := file_reader.read_file(fname) 89 | if err != nil { 90 | return 91 | } 92 | m.process_package_data(data) 93 | } 94 | } 95 | 96 | func (m *package_file_cache) process_package_data(data []byte) { 97 | m.scope = new_named_scope(g_universe_scope, m.name) 98 | 99 | // find import section 100 | i := bytes.Index(data, []byte{'\n', '$', '$'}) 101 | if i == -1 { 102 | panic(fmt.Sprintf("Can't find the import section in the package file %s", m.name)) 103 | } 104 | data = data[i+len("\n$$"):] 105 | 106 | // main package 107 | m.main = new_decl(m.name, decl_package, nil) 108 | // create map for other packages 109 | m.others = make(map[string]*decl) 110 | 111 | var pp package_parser 112 | if data[0] == 'B' { 113 | // binary format, skip 'B\n' 114 | data = data[2:] 115 | if len(data) > 0 && data[0] == 'i' { 116 | var p gc_ibin_parser 117 | p.init(data[1:], m) 118 | pp = &p 119 | } else { 120 | var p gc_bin_parser 121 | p.init(data, m) 122 | pp = &p 123 | } 124 | } else { 125 | // textual format, find the beginning of the package clause 126 | i = bytes.Index(data, []byte{'p', 'a', 'c', 'k', 'a', 'g', 'e'}) 127 | if i == -1 { 128 | panic("Can't find the package clause") 129 | } 130 | data = data[i:] 131 | 132 | var p gc_parser 133 | p.init(data, m) 134 | pp = &p 135 | } 136 | 137 | prefix := "!" + m.name + "!" 138 | pp.parse_export(func(pkg string, decl ast.Decl) { 139 | anonymify_ast(decl, decl_foreign, m.scope) 140 | if pkg == "" || strings.HasPrefix(pkg, prefix) { 141 | // main package 142 | add_ast_decl_to_package(m.main, decl, m.scope) 143 | } else { 144 | // others 145 | if _, ok := m.others[pkg]; !ok { 146 | m.others[pkg] = new_decl(pkg, decl_package, nil) 147 | } 148 | add_ast_decl_to_package(m.others[pkg], decl, m.scope) 149 | } 150 | }) 151 | 152 | // hack, add ourselves to the package scope 153 | mainName := "!" + m.name + "!" + m.defalias 154 | m.add_package_to_scope(mainName, m.name) 155 | 156 | // replace dummy package decls in package scope to actual packages 157 | for key := range m.scope.entities { 158 | if !strings.HasPrefix(key, "!") { 159 | continue 160 | } 161 | pkg, ok := m.others[key] 162 | if !ok && key == mainName { 163 | pkg = m.main 164 | } 165 | m.scope.replace_decl(key, pkg) 166 | } 167 | } 168 | 169 | func (m *package_file_cache) add_package_to_scope(alias, realname string) { 170 | d := new_decl(realname, decl_package, nil) 171 | m.scope.add_decl(alias, d) 172 | } 173 | 174 | func add_ast_decl_to_package(pkg *decl, decl ast.Decl, scope *scope) { 175 | foreach_decl(decl, func(data *foreach_decl_struct) { 176 | class := ast_decl_class(data.decl) 177 | for i, name := range data.names { 178 | typ, v, vi := data.type_value_index(i) 179 | 180 | d := new_decl_full(name.Name, class, decl_foreign|ast_decl_flags(data.decl), typ, v, vi, scope) 181 | if d == nil { 182 | return 183 | } 184 | 185 | if !name.IsExported() && d.class != decl_type { 186 | return 187 | } 188 | 189 | methodof := method_of(data.decl) 190 | if methodof != "" { 191 | decl := pkg.find_child(methodof) 192 | if decl != nil { 193 | decl.add_child(d) 194 | } else { 195 | decl = new_decl(methodof, decl_methods_stub, scope) 196 | decl.add_child(d) 197 | pkg.add_child(decl) 198 | } 199 | } else { 200 | decl := pkg.find_child(d.name) 201 | if decl != nil { 202 | decl.expand_or_replace(d) 203 | } else { 204 | pkg.add_child(d) 205 | } 206 | } 207 | } 208 | }) 209 | } 210 | 211 | //------------------------------------------------------------------------- 212 | // package_cache 213 | //------------------------------------------------------------------------- 214 | 215 | type package_cache map[string]*package_file_cache 216 | 217 | func new_package_cache() package_cache { 218 | m := make(package_cache) 219 | 220 | // add built-in "unsafe" package 221 | m.add_builtin_unsafe_package() 222 | 223 | return m 224 | } 225 | 226 | // Function fills 'ps' set with packages from 'packages' import information. 227 | // In case if package is not in the cache, it creates one and adds one to the cache. 228 | func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) { 229 | for _, m := range pkgs { 230 | if _, ok := ps[m.abspath]; ok { 231 | continue 232 | } 233 | 234 | if mod, ok := c[m.abspath]; ok { 235 | ps[m.abspath] = mod 236 | } else { 237 | mod = new_package_file_cache(m.abspath, m.path) 238 | ps[m.abspath] = mod 239 | c[m.abspath] = mod 240 | } 241 | } 242 | } 243 | 244 | var g_builtin_unsafe_package = []byte(` 245 | import 246 | $$ 247 | package unsafe 248 | type @"".Pointer uintptr 249 | func @"".Offsetof (? any) uintptr 250 | func @"".Sizeof (? any) uintptr 251 | func @"".Alignof (? any) uintptr 252 | 253 | $$ 254 | `) 255 | 256 | func (c package_cache) add_builtin_unsafe_package() { 257 | pkg := new_package_file_cache_forever("unsafe", "unsafe") 258 | pkg.process_package_data(g_builtin_unsafe_package) 259 | c["unsafe"] = pkg 260 | } 261 | -------------------------------------------------------------------------------- /pre_go17.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7,!go1.8 2 | 3 | package main 4 | 5 | func init() { 6 | knownPackageIdents["context"] = "golang.org/x/net/context" 7 | } 8 | -------------------------------------------------------------------------------- /ripper.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/scanner" 5 | "go/token" 6 | ) 7 | 8 | // All the code in this file serves single purpose: 9 | // It separates a function with the cursor inside and the rest of the code. I'm 10 | // doing that, because sometimes parser is not able to recover itself from an 11 | // error and the autocompletion results become less complete. 12 | 13 | type tok_pos_pair struct { 14 | tok token.Token 15 | pos token.Pos 16 | } 17 | 18 | type tok_collection struct { 19 | tokens []tok_pos_pair 20 | fset *token.FileSet 21 | } 22 | 23 | func (this *tok_collection) next(s *scanner.Scanner) bool { 24 | pos, tok, _ := s.Scan() 25 | if tok == token.EOF { 26 | return false 27 | } 28 | 29 | this.tokens = append(this.tokens, tok_pos_pair{tok, pos}) 30 | return true 31 | } 32 | 33 | func (this *tok_collection) find_decl_beg(pos int) int { 34 | lowest := 0 35 | lowpos := -1 36 | lowi := -1 37 | cur := 0 38 | for i := pos; i >= 0; i-- { 39 | t := this.tokens[i] 40 | switch t.tok { 41 | case token.RBRACE: 42 | cur++ 43 | case token.LBRACE: 44 | cur-- 45 | } 46 | 47 | if cur < lowest { 48 | lowest = cur 49 | lowpos = this.fset.Position(t.pos).Offset 50 | lowi = i 51 | } 52 | } 53 | 54 | cur = lowest 55 | for i := lowi - 1; i >= 0; i-- { 56 | t := this.tokens[i] 57 | switch t.tok { 58 | case token.RBRACE: 59 | cur++ 60 | case token.LBRACE: 61 | cur-- 62 | } 63 | if t.tok == token.SEMICOLON && cur == lowest { 64 | lowpos = this.fset.Position(t.pos).Offset 65 | break 66 | } 67 | } 68 | 69 | return lowpos 70 | } 71 | 72 | func (this *tok_collection) find_decl_end(pos int) int { 73 | highest := 0 74 | highpos := -1 75 | cur := 0 76 | 77 | if this.tokens[pos].tok == token.LBRACE { 78 | pos++ 79 | } 80 | 81 | for i := pos; i < len(this.tokens); i++ { 82 | t := this.tokens[i] 83 | switch t.tok { 84 | case token.RBRACE: 85 | cur++ 86 | case token.LBRACE: 87 | cur-- 88 | } 89 | 90 | if cur > highest { 91 | highest = cur 92 | highpos = this.fset.Position(t.pos).Offset 93 | } 94 | } 95 | 96 | return highpos 97 | } 98 | 99 | func (this *tok_collection) find_outermost_scope(cursor int) (int, int) { 100 | pos := 0 101 | 102 | for i, t := range this.tokens { 103 | if cursor <= this.fset.Position(t.pos).Offset { 104 | break 105 | } 106 | pos = i 107 | } 108 | 109 | return this.find_decl_beg(pos), this.find_decl_end(pos) 110 | } 111 | 112 | // return new cursor position, file without ripped part and the ripped part itself 113 | // variants: 114 | // new-cursor, file-without-ripped-part, ripped-part 115 | // old-cursor, file, nil 116 | func (this *tok_collection) rip_off_decl(file []byte, cursor int) (int, []byte, []byte) { 117 | this.fset = token.NewFileSet() 118 | var s scanner.Scanner 119 | s.Init(this.fset.AddFile("", this.fset.Base(), len(file)), file, nil, scanner.ScanComments) 120 | for this.next(&s) { 121 | } 122 | 123 | beg, end := this.find_outermost_scope(cursor) 124 | if beg == -1 || end == -1 { 125 | return cursor, file, nil 126 | } 127 | 128 | ripped := make([]byte, end+1-beg) 129 | copy(ripped, file[beg:end+1]) 130 | 131 | newfile := make([]byte, len(file)-len(ripped)) 132 | copy(newfile, file[:beg]) 133 | copy(newfile[beg:], file[end+1:]) 134 | 135 | return cursor - beg, newfile, ripped 136 | } 137 | 138 | func rip_off_decl(file []byte, cursor int) (int, []byte, []byte) { 139 | var tc tok_collection 140 | return tc.rip_off_decl(file, cursor) 141 | } 142 | -------------------------------------------------------------------------------- /rpc.go: -------------------------------------------------------------------------------- 1 | // WARNING! Autogenerated by goremote, don't touch. 2 | 3 | package main 4 | 5 | import ( 6 | "net/rpc" 7 | ) 8 | 9 | type RPC struct { 10 | } 11 | 12 | // wrapper for: server_auto_complete 13 | 14 | type Args_auto_complete struct { 15 | Arg0 []byte 16 | Arg1 string 17 | Arg2 int 18 | Arg3 go_build_context 19 | } 20 | type Reply_auto_complete struct { 21 | Arg0 []candidate 22 | Arg1 int 23 | } 24 | 25 | func (r *RPC) RPC_auto_complete(args *Args_auto_complete, reply *Reply_auto_complete) error { 26 | reply.Arg0, reply.Arg1 = server_auto_complete(args.Arg0, args.Arg1, args.Arg2, args.Arg3) 27 | return nil 28 | } 29 | func client_auto_complete(cli *rpc.Client, Arg0 []byte, Arg1 string, Arg2 int, Arg3 go_build_context) (c []candidate, d int) { 30 | var args Args_auto_complete 31 | var reply Reply_auto_complete 32 | args.Arg0 = Arg0 33 | args.Arg1 = Arg1 34 | args.Arg2 = Arg2 35 | args.Arg3 = Arg3 36 | err := cli.Call("RPC.RPC_auto_complete", &args, &reply) 37 | if err != nil { 38 | panic(err) 39 | } 40 | return reply.Arg0, reply.Arg1 41 | } 42 | 43 | // wrapper for: server_close 44 | 45 | type Args_close struct { 46 | Arg0 int 47 | } 48 | type Reply_close struct { 49 | Arg0 int 50 | } 51 | 52 | func (r *RPC) RPC_close(args *Args_close, reply *Reply_close) error { 53 | reply.Arg0 = server_close(args.Arg0) 54 | return nil 55 | } 56 | func client_close(cli *rpc.Client, Arg0 int) int { 57 | var args Args_close 58 | var reply Reply_close 59 | args.Arg0 = Arg0 60 | err := cli.Call("RPC.RPC_close", &args, &reply) 61 | if err != nil { 62 | panic(err) 63 | } 64 | return reply.Arg0 65 | } 66 | 67 | // wrapper for: server_status 68 | 69 | type Args_status struct { 70 | Arg0 int 71 | } 72 | type Reply_status struct { 73 | Arg0 string 74 | } 75 | 76 | func (r *RPC) RPC_status(args *Args_status, reply *Reply_status) error { 77 | reply.Arg0 = server_status(args.Arg0) 78 | return nil 79 | } 80 | func client_status(cli *rpc.Client, Arg0 int) string { 81 | var args Args_status 82 | var reply Reply_status 83 | args.Arg0 = Arg0 84 | err := cli.Call("RPC.RPC_status", &args, &reply) 85 | if err != nil { 86 | panic(err) 87 | } 88 | return reply.Arg0 89 | } 90 | 91 | // wrapper for: server_drop_cache 92 | 93 | type Args_drop_cache struct { 94 | Arg0 int 95 | } 96 | type Reply_drop_cache struct { 97 | Arg0 int 98 | } 99 | 100 | func (r *RPC) RPC_drop_cache(args *Args_drop_cache, reply *Reply_drop_cache) error { 101 | reply.Arg0 = server_drop_cache(args.Arg0) 102 | return nil 103 | } 104 | func client_drop_cache(cli *rpc.Client, Arg0 int) int { 105 | var args Args_drop_cache 106 | var reply Reply_drop_cache 107 | args.Arg0 = Arg0 108 | err := cli.Call("RPC.RPC_drop_cache", &args, &reply) 109 | if err != nil { 110 | panic(err) 111 | } 112 | return reply.Arg0 113 | } 114 | 115 | // wrapper for: server_set 116 | 117 | type Args_set struct { 118 | Arg0, Arg1 string 119 | } 120 | type Reply_set struct { 121 | Arg0 string 122 | } 123 | 124 | func (r *RPC) RPC_set(args *Args_set, reply *Reply_set) error { 125 | reply.Arg0 = server_set(args.Arg0, args.Arg1) 126 | return nil 127 | } 128 | func client_set(cli *rpc.Client, Arg0, Arg1 string) string { 129 | var args Args_set 130 | var reply Reply_set 131 | args.Arg0 = Arg0 132 | args.Arg1 = Arg1 133 | err := cli.Call("RPC.RPC_set", &args, &reply) 134 | if err != nil { 135 | panic(err) 136 | } 137 | return reply.Arg0 138 | } 139 | 140 | // wrapper for: server_options 141 | 142 | type Args_options struct { 143 | Arg0 int 144 | } 145 | type Reply_options struct { 146 | Arg0 string 147 | } 148 | 149 | func (r *RPC) RPC_options(args *Args_options, reply *Reply_options) error { 150 | reply.Arg0 = server_options(args.Arg0) 151 | return nil 152 | } 153 | func client_options(cli *rpc.Client, Arg0 int) string { 154 | var args Args_options 155 | var reply Reply_options 156 | args.Arg0 = Arg0 157 | err := cli.Call("RPC.RPC_options", &args, &reply) 158 | if err != nil { 159 | panic(err) 160 | } 161 | return reply.Arg0 162 | } 163 | -------------------------------------------------------------------------------- /scope.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //------------------------------------------------------------------------- 4 | // scope 5 | //------------------------------------------------------------------------- 6 | 7 | type scope struct { 8 | // the package name that this scope resides in 9 | pkgname string 10 | parent *scope // nil for universe scope 11 | entities map[string]*decl 12 | } 13 | 14 | func new_named_scope(outer *scope, name string) *scope { 15 | s := new_scope(outer) 16 | s.pkgname = name 17 | return s 18 | } 19 | 20 | func new_scope(outer *scope) *scope { 21 | s := new(scope) 22 | if outer != nil { 23 | s.pkgname = outer.pkgname 24 | } 25 | s.parent = outer 26 | s.entities = make(map[string]*decl) 27 | return s 28 | } 29 | 30 | // returns: new, prev 31 | func advance_scope(s *scope) (*scope, *scope) { 32 | if len(s.entities) == 0 { 33 | return s, s.parent 34 | } 35 | return new_scope(s), s 36 | } 37 | 38 | // adds declaration or returns an existing one 39 | func (s *scope) add_named_decl(d *decl) *decl { 40 | return s.add_decl(d.name, d) 41 | } 42 | 43 | func (s *scope) add_decl(name string, d *decl) *decl { 44 | decl, ok := s.entities[name] 45 | if !ok { 46 | s.entities[name] = d 47 | return d 48 | } 49 | return decl 50 | } 51 | 52 | func (s *scope) replace_decl(name string, d *decl) { 53 | s.entities[name] = d 54 | } 55 | 56 | func (s *scope) merge_decl(d *decl) { 57 | decl, ok := s.entities[d.name] 58 | if !ok { 59 | s.entities[d.name] = d 60 | } else { 61 | decl := decl.deep_copy() 62 | decl.expand_or_replace(d) 63 | s.entities[d.name] = decl 64 | } 65 | } 66 | 67 | func (s *scope) lookup(name string) *decl { 68 | decl, ok := s.entities[name] 69 | if !ok { 70 | if s.parent != nil { 71 | return s.parent.lookup(name) 72 | } else { 73 | return nil 74 | } 75 | } 76 | return decl 77 | } 78 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/build" 7 | "log" 8 | "net" 9 | "net/rpc" 10 | "os" 11 | "path/filepath" 12 | "reflect" 13 | "runtime" 14 | "time" 15 | ) 16 | 17 | func do_server() int { 18 | g_config.read() 19 | if g_config.ForceDebugOutput != "" { 20 | // forcefully enable debugging and redirect logging into the 21 | // specified file 22 | *g_debug = true 23 | f, err := os.Create(g_config.ForceDebugOutput) 24 | if err != nil { 25 | panic(err) 26 | } 27 | log.SetOutput(f) 28 | } 29 | 30 | addr := *g_addr 31 | if *g_sock == "unix" { 32 | addr = get_socket_filename() 33 | if file_exists(addr) { 34 | log.Printf("unix socket: '%s' already exists\n", addr) 35 | return 1 36 | } 37 | } 38 | g_daemon = new_daemon(*g_sock, addr) 39 | if *g_sock == "unix" { 40 | // cleanup unix socket file 41 | defer os.Remove(addr) 42 | } 43 | 44 | rpc.Register(new(RPC)) 45 | 46 | g_daemon.loop() 47 | return 0 48 | } 49 | 50 | //------------------------------------------------------------------------- 51 | // daemon 52 | //------------------------------------------------------------------------- 53 | 54 | type daemon struct { 55 | listener net.Listener 56 | cmd_in chan int 57 | autocomplete *auto_complete_context 58 | pkgcache package_cache 59 | declcache *decl_cache 60 | context package_lookup_context 61 | } 62 | 63 | func new_daemon(network, address string) *daemon { 64 | var err error 65 | 66 | d := new(daemon) 67 | d.listener, err = net.Listen(network, address) 68 | if err != nil { 69 | panic(err) 70 | } 71 | 72 | d.cmd_in = make(chan int, 1) 73 | d.pkgcache = new_package_cache() 74 | d.declcache = new_decl_cache(&d.context) 75 | d.autocomplete = new_auto_complete_context(d.pkgcache, d.declcache) 76 | return d 77 | } 78 | 79 | func (this *daemon) drop_cache() { 80 | this.pkgcache = new_package_cache() 81 | this.declcache = new_decl_cache(&this.context) 82 | this.autocomplete = new_auto_complete_context(this.pkgcache, this.declcache) 83 | } 84 | 85 | const ( 86 | daemon_close = iota 87 | ) 88 | 89 | func (this *daemon) loop() { 90 | conn_in := make(chan net.Conn) 91 | go func() { 92 | for { 93 | c, err := this.listener.Accept() 94 | if err != nil { 95 | panic(err) 96 | } 97 | conn_in <- c 98 | } 99 | }() 100 | 101 | timeout := time.Duration(g_config.CloseTimeout) * time.Second 102 | countdown := time.NewTimer(timeout) 103 | 104 | for { 105 | // handle connections or server CMDs (currently one CMD) 106 | select { 107 | case c := <-conn_in: 108 | rpc.ServeConn(c) 109 | countdown.Reset(timeout) 110 | runtime.GC() 111 | case cmd := <-this.cmd_in: 112 | switch cmd { 113 | case daemon_close: 114 | return 115 | } 116 | case <-countdown.C: 117 | return 118 | } 119 | } 120 | } 121 | 122 | func (this *daemon) close() { 123 | this.cmd_in <- daemon_close 124 | } 125 | 126 | var g_daemon *daemon 127 | 128 | //------------------------------------------------------------------------- 129 | // server_* functions 130 | // 131 | // Corresponding client_* functions are autogenerated by goremote. 132 | //------------------------------------------------------------------------- 133 | 134 | func server_auto_complete(file []byte, filename string, cursor int, context_packed go_build_context) (c []candidate, d int) { 135 | context := unpack_build_context(&context_packed) 136 | defer func() { 137 | if err := recover(); err != nil { 138 | print_backtrace(err) 139 | c = []candidate{ 140 | {"PANIC", "PANIC", decl_invalid, "panic"}, 141 | } 142 | 143 | // drop cache 144 | g_daemon.drop_cache() 145 | } 146 | }() 147 | // TODO: Probably we don't care about comparing all the fields, checking GOROOT and GOPATH 148 | // should be enough. 149 | if !reflect.DeepEqual(g_daemon.context.Context, context.Context) { 150 | g_daemon.context = context 151 | g_daemon.drop_cache() 152 | } 153 | switch g_config.PackageLookupMode { 154 | case "bzl": 155 | // when package lookup mode is bzl, we set GOPATH to "" explicitly and 156 | // BzlProjectRoot becomes valid (or empty) 157 | var err error 158 | g_daemon.context.GOPATH = "" 159 | g_daemon.context.BzlProjectRoot, err = find_bzl_project_root(g_config.LibPath, filename) 160 | if *g_debug && err != nil { 161 | log.Printf("Bzl project root not found: %s", err) 162 | } 163 | case "gb": 164 | // when package lookup mode is gb, we set GOPATH to "" explicitly and 165 | // GBProjectRoot becomes valid (or empty) 166 | var err error 167 | g_daemon.context.GOPATH = "" 168 | g_daemon.context.GBProjectRoot, err = find_gb_project_root(filename) 169 | if *g_debug && err != nil { 170 | log.Printf("Gb project root not found: %s", err) 171 | } 172 | case "go": 173 | // get current package path for GO15VENDOREXPERIMENT hack 174 | g_daemon.context.CurrentPackagePath = "" 175 | pkg, err := g_daemon.context.ImportDir(filepath.Dir(filename), build.FindOnly) 176 | if err == nil { 177 | if *g_debug { 178 | log.Printf("Go project path: %s", pkg.ImportPath) 179 | } 180 | g_daemon.context.CurrentPackagePath = pkg.ImportPath 181 | } else if *g_debug { 182 | log.Printf("Go project path not found: %s", err) 183 | } 184 | } 185 | if *g_debug { 186 | var buf bytes.Buffer 187 | log.Printf("Got autocompletion request for '%s'\n", filename) 188 | log.Printf("Cursor at: %d\n", cursor) 189 | if cursor > len(file) || cursor < 0 { 190 | log.Println("ERROR! Cursor is outside of the boundaries of the buffer, " + 191 | "this is most likely a text editor plugin bug. Text editor is responsible " + 192 | "for passing the correct cursor position to gocode.") 193 | } else { 194 | buf.WriteString("-------------------------------------------------------\n") 195 | buf.Write(file[:cursor]) 196 | buf.WriteString("#") 197 | buf.Write(file[cursor:]) 198 | log.Print(buf.String()) 199 | log.Println("-------------------------------------------------------") 200 | } 201 | } 202 | candidates, d := g_daemon.autocomplete.apropos(file, filename, cursor) 203 | if *g_debug { 204 | log.Printf("Offset: %d\n", d) 205 | log.Printf("Number of candidates found: %d\n", len(candidates)) 206 | log.Printf("Candidates are:\n") 207 | for _, c := range candidates { 208 | abbr := fmt.Sprintf("%s %s %s", c.Class, c.Name, c.Type) 209 | if c.Class == decl_func { 210 | abbr = fmt.Sprintf("%s %s%s", c.Class, c.Name, c.Type[len("func"):]) 211 | } 212 | log.Printf(" %s\n", abbr) 213 | } 214 | log.Println("=======================================================") 215 | } 216 | return candidates, d 217 | } 218 | 219 | func server_close(notused int) int { 220 | g_daemon.close() 221 | return 0 222 | } 223 | 224 | func server_status(notused int) string { 225 | return g_daemon.autocomplete.status() 226 | } 227 | 228 | func server_drop_cache(notused int) int { 229 | // drop cache 230 | g_daemon.drop_cache() 231 | return 0 232 | } 233 | 234 | func server_set(key, value string) string { 235 | if key == "\x00" { 236 | return g_config.list() 237 | } else if value == "\x00" { 238 | return g_config.list_option(key) 239 | } 240 | // drop cache on settings changes 241 | g_daemon.drop_cache() 242 | return g_config.set_option(key, value) 243 | } 244 | 245 | func server_options(notused int) string { 246 | return g_config.options() 247 | } 248 | -------------------------------------------------------------------------------- /subl3/README.md: -------------------------------------------------------------------------------- 1 | # Sublime Text 3 plugin 2 | 3 | If you want full Go experience in sublime, use [GoSublime](https://github.com/DisposaBoy/GoSublime). 4 | 5 | This plugin is written by me (nsf) as a result of frustration with GoSublime. I wanted something simpler and plugin has to use system version of the gocode. As you may know, GoSublime uses a fork of gocode, which is integrated into its own daemon called MarGo (as far as I know). 6 | 7 | The plugin does: 8 | 9 | 1. Basic gocode autocompletion. I did my best presenting the results to the user. Maybe it's possible to improve that part a bit, not quite sure yet. For functions I use "{**class**} {**name**}\t{**returns**}", for everything else "{**class**} {**name**}\t{**type**}". In addition to that functions are properly augmented with argument snippets. 10 | 11 | 2. Gofmt on save. Here I use difflib to calculate differences, which results in line by line changes. GoSublime uses [google-diff-match-patch](https://code.google.com/archive/p/google-diff-match-patch/) library, which calculates changes on finer granularity, maybe I should switch to that lib as well. 12 | 13 | I don't have any big plans on this plugin. The reason why I moved to sublime in the first place is, again, frustration, but with Atom (too slow). We'll see how it goes. 14 | 15 | Oh yes, this plugin uses GoSublime syntax files for Go. Well, they use a fork of gocode, I'll use the fork of their syntax files, fair deal. 16 | -------------------------------------------------------------------------------- /subl3/gocode.py: -------------------------------------------------------------------------------- 1 | import sublime, sublime_plugin, subprocess, difflib 2 | 3 | # go to balanced pair, e.g.: 4 | # ((abc(def))) 5 | # ^ 6 | # \--------->^ 7 | # 8 | # returns -1 on failure 9 | def skip_to_balanced_pair(str, i, open, close): 10 | count = 1 11 | i += 1 12 | while i < len(str): 13 | if str[i] == open: 14 | count += 1 15 | elif str[i] == close: 16 | count -= 1 17 | 18 | if count == 0: 19 | break 20 | i += 1 21 | if i >= len(str): 22 | return -1 23 | return i 24 | 25 | # split balanced parens string using comma as separator 26 | # e.g.: "ab, (1, 2), cd" -> ["ab", "(1, 2)", "cd"] 27 | # filters out empty strings 28 | def split_balanced(s): 29 | out = [] 30 | i = 0 31 | beg = 0 32 | while i < len(s): 33 | if s[i] == ',': 34 | out.append(s[beg:i].strip()) 35 | beg = i+1 36 | i += 1 37 | elif s[i] == '(': 38 | i = skip_to_balanced_pair(s, i, "(", ")") 39 | if i == -1: 40 | i = len(s) 41 | else: 42 | i += 1 43 | 44 | out.append(s[beg:i].strip()) 45 | return list(filter(bool, out)) 46 | 47 | 48 | def extract_arguments_and_returns(sig): 49 | sig = sig.strip() 50 | if not sig.startswith("func"): 51 | return [], [] 52 | 53 | # find first pair of parens, these are arguments 54 | beg = sig.find("(") 55 | if beg == -1: 56 | return [], [] 57 | end = skip_to_balanced_pair(sig, beg, "(", ")") 58 | if end == -1: 59 | return [], [] 60 | args = split_balanced(sig[beg+1:end]) 61 | 62 | # find the rest of the string, these are returns 63 | sig = sig[end+1:].strip() 64 | sig = sig[1:-1] if sig.startswith("(") and sig.endswith(")") else sig 65 | returns = split_balanced(sig) 66 | 67 | return args, returns 68 | 69 | # takes gocode's candidate and returns sublime's hint and subj 70 | def hint_and_subj(cls, name, type): 71 | subj = name 72 | if cls == "func": 73 | hint = cls + " " + name 74 | args, returns = extract_arguments_and_returns(type) 75 | if returns: 76 | hint += "\t" + ", ".join(returns) 77 | if args: 78 | sargs = [] 79 | for i, a in enumerate(args): 80 | ea = a.replace("{", "\\{").replace("}", "\\}") 81 | sargs.append("${{{0}:{1}}}".format(i+1, ea)) 82 | subj += "(" + ", ".join(sargs) + ")" 83 | else: 84 | subj += "()" 85 | else: 86 | hint = cls + " " + name + "\t" + type 87 | return hint, subj 88 | 89 | def diff_sanity_check(a, b): 90 | if a != b: 91 | raise Exception("diff sanity check mismatch\n-%s\n+%s" % (a, b)) 92 | 93 | class GocodeGofmtCommand(sublime_plugin.TextCommand): 94 | def run(self, edit): 95 | view = self.view 96 | src = view.substr(sublime.Region(0, view.size())) 97 | gofmt = subprocess.Popen(["gofmt"], 98 | stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 99 | sout, serr = gofmt.communicate(src.encode()) 100 | if gofmt.returncode != 0: 101 | print(serr.decode(), end="") 102 | return 103 | 104 | newsrc = sout.decode() 105 | diff = difflib.ndiff(src.splitlines(), newsrc.splitlines()) 106 | i = 0 107 | for line in diff: 108 | if line.startswith("?"): # skip hint lines 109 | continue 110 | 111 | l = (len(line)-2)+1 112 | if line.startswith("-"): 113 | diff_sanity_check(view.substr(sublime.Region(i, i+l-1)), line[2:]) 114 | view.erase(edit, sublime.Region(i, i+l)) 115 | elif line.startswith("+"): 116 | view.insert(edit, i, line[2:]+"\n") 117 | i += l 118 | else: 119 | diff_sanity_check(view.substr(sublime.Region(i, i+l-1)), line[2:]) 120 | i += l 121 | 122 | class Gocode(sublime_plugin.EventListener): 123 | """Sublime Text gocode integration.""" 124 | 125 | def __init__(self): 126 | self._running = False 127 | self._completions = None 128 | self._location = 0 129 | self._prefix = "" 130 | 131 | def fetch_query_completions(self, view, prefix, location): 132 | """Fetches the query completions of for the given location 133 | 134 | Execute gocode and parse the returned csv. If the cursor location did not change, a 135 | result got returned and the current cursor location is still at the same position will the query completions 136 | method be called again (to render the results). 137 | 138 | :param view: currently active sublime view 139 | :type view: sublime.View 140 | :param prefix: string for completions 141 | :type prefix: basestring 142 | :param locations: offset from beginning 143 | :type locations: int 144 | """ 145 | 146 | self._running = True 147 | self._location = location 148 | 149 | src = view.substr(sublime.Region(0, view.size())) 150 | filename = view.file_name() 151 | cloc = "c{0}".format(location) 152 | gocode = subprocess.Popen(["gocode", "-f=csv", "autocomplete", filename, cloc], 153 | stdin=subprocess.PIPE, stdout=subprocess.PIPE) 154 | out = gocode.communicate(src.encode())[0].decode() 155 | 156 | result = [] 157 | for line in filter(bool, out.split("\n")): 158 | arg = line.split(",,") 159 | hint, subj = hint_and_subj(arg[0], arg[1], arg[2]) 160 | result.append([hint, subj]) 161 | 162 | # Exit conditions: 163 | if len(result) == 0: 164 | return 165 | 166 | if self._prefix != prefix: 167 | return 168 | 169 | # Check if this query completions request is for the "latest" location 170 | if self._location != location: 171 | return 172 | 173 | self._completions = result 174 | self._running = False 175 | 176 | self.open_query_completions(view) 177 | 178 | def open_query_completions(self, view): 179 | """Opens (forced) the sublime autocomplete window""" 180 | 181 | view.run_command("hide_auto_complete") 182 | sublime.set_timeout( 183 | lambda: view.run_command("auto_complete") 184 | ) 185 | 186 | def on_query_completions(self, view, prefix, locations): 187 | """Sublime autocomplete event handler. 188 | 189 | Get completions depends on current cursor position and return 190 | them as list of ('possible completion', 'completion type') 191 | 192 | :param view: currently active sublime view 193 | :type view: sublime.View 194 | :param prefix: string for completions 195 | :type prefix: basestring 196 | :param locations: offset from beginning 197 | :type locations: int 198 | 199 | :return: list of tuple(str, str) 200 | """ 201 | 202 | loc = locations[0] 203 | 204 | if not view.match_selector(loc, "source.go"): 205 | return [] 206 | 207 | if self._completions: 208 | completions = self._completions 209 | 210 | self._completions = None 211 | self._prefix = "" 212 | 213 | return completions 214 | 215 | if self._running and len(prefix) != 0: 216 | return [] 217 | 218 | self._prefix = prefix 219 | 220 | sublime.set_timeout_async( 221 | lambda: self.fetch_query_completions(view, prefix, loc) 222 | ) 223 | 224 | return [] 225 | 226 | def on_pre_save(self, view): 227 | if not view.match_selector(0, "source.go"): 228 | return 229 | view.run_command('gocode_gofmt') -------------------------------------------------------------------------------- /subl3/syntax/GoSublime-Go.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | comment 6 | Based on work from github.com/frou/GoFeather and github.com/DisposaBoy/GoSublime 7 | fileTypes 8 | 9 | go 10 | 11 | firstLineMatch 12 | -[*]-( Mode:)? Go -[*]- 13 | keyEquivalent 14 | ^~G 15 | name 16 | GoSublime: Go 17 | patterns 18 | 19 | 20 | begin 21 | /\* 22 | end 23 | \*/ 24 | name 25 | comment.block.go 26 | 27 | 28 | begin 29 | // 30 | end 31 | \z 32 | name 33 | comment.line.double-slash.go 34 | 35 | 36 | begin 37 | " 38 | beginCaptures 39 | 40 | 0 41 | 42 | name 43 | punctuation.definition.string.begin.go 44 | 45 | 46 | end 47 | " 48 | endCaptures 49 | 50 | 0 51 | 52 | name 53 | punctuation.definition.string.end.go 54 | 55 | 56 | name 57 | string.quoted.double.go 58 | patterns 59 | 60 | 61 | include 62 | #string_placeholder 63 | 64 | 65 | include 66 | #string_escaped_char 67 | 68 | 69 | 70 | 71 | begin 72 | ` 73 | beginCaptures 74 | 75 | 0 76 | 77 | name 78 | punctuation.definition.string.begin.go 79 | 80 | 81 | end 82 | ` 83 | endCaptures 84 | 85 | 0 86 | 87 | name 88 | punctuation.definition.string.end.go 89 | 90 | 91 | name 92 | string.quoted.raw.go 93 | patterns 94 | 95 | 96 | include 97 | #string_placeholder 98 | 99 | 100 | include 101 | source.gotemplate 102 | 103 | 104 | 105 | 106 | match 107 | \b(true|false|nil|iota)\b 108 | name 109 | constant.language.go 110 | 111 | 112 | match 113 | \b((\d+\.(\d+)?([eE][+-]?\d+)?|\d+[eE][+-]?\d+|\.\d+([eE][+-]?\d+)?)i?)\b 114 | name 115 | constant.numeric.floating-point.go 116 | 117 | 118 | match 119 | \b(\d+i|0[xX][0-9A-Fa-f]+|0[0-7]*|[1-9][0-9]*)\b 120 | name 121 | constant.numeric.integer.go 122 | 123 | 124 | match 125 | '(?:[^'\\]|\\(?:\\|[abfnrtv']|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|[0-7]{3}))' 126 | name 127 | constant.other.rune.go 128 | 129 | 130 | match 131 | \b(bool|byte|complex(64|128)|error|float(32|64)|rune|string|u?int(8|16|32|64)?|uintptr)\b 132 | name 133 | storage.type.go 134 | 135 | 136 | comment 137 | A subset of keyword.other.go for flow control keywords. 138 | match 139 | \b(break|case|continue|default|defer|else|for|go|goto|if|range|return|select|switch)\b 140 | name 141 | keyword.control.go 142 | 143 | 144 | match 145 | \b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b 146 | name 147 | keyword.other.go 148 | 149 | 150 | captures 151 | 152 | 0 153 | 154 | name 155 | variable.other.go 156 | 157 | 1 158 | 159 | name 160 | keyword.operator.initialize.go 161 | 162 | 163 | comment 164 | This matches the 'x := 0' style of variable declaration. 165 | match 166 | (?:[[:alpha:]_][[:alnum:]_]*)(?:,\s+[[:alpha:]_][[:alnum:]_]*)*\s*(:=) 167 | name 168 | meta.initialization.short.go 169 | 170 | 171 | match 172 | (?<=(\Afunc|...\))\s)\b(\w+)\b(?=\() 173 | name 174 | entity.name.function.go 175 | 176 | 177 | match 178 | (?<=(\sfunc|....\))\s)\b(\w+)\b(?=\() 179 | name 180 | entity.name.function.go 181 | 182 | 183 | match 184 | (?<=\Atype\s)\b(\w+)\b 185 | name 186 | entity.name.type.go 187 | 188 | 189 | match 190 | (?<=\stype\s)\b(\w+)\b 191 | name 192 | entity.name.type.go 193 | 194 | 195 | match 196 | \b(append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)\b 197 | name 198 | support.function.builtin.go 199 | 200 | 201 | match 202 | \b(\w+)\b(?=\() 203 | name 204 | support.function.go 205 | 206 | 207 | match 208 | (<-) 209 | name 210 | keyword.operator.channel.go 211 | 212 | 213 | match 214 | (==|!=|<|<=|>|>=) 215 | name 216 | keyword.operator.comparison.go 217 | 218 | 219 | match 220 | (&&|[|]{2}|!) 221 | name 222 | keyword.operator.logical.go 223 | 224 | 225 | match 226 | ([+]{2}) 227 | name 228 | keyword.operator.increment.go 229 | 230 | 231 | match 232 | (--) 233 | name 234 | keyword.decrement.go 235 | 236 | 237 | match 238 | (=|(?:[+]|-|[|]|^|[*]|/|%|<<|>>|&|&^)=) 239 | name 240 | keyword.operator.assignment.go 241 | 242 | 243 | match 244 | ([+]|-|[*]|/|%|&|[|]|^|&^|<<|>>) 245 | name 246 | keyword.operator.arithmetic.go 247 | 248 | 249 | match 250 | (;) 251 | name 252 | keyword.operator.semi-colon.go 253 | 254 | 255 | match 256 | (,) 257 | name 258 | punctuation.definition.comma.go 259 | 260 | 261 | match 262 | ([.]) 263 | name 264 | punctuation.definition.dot.go 265 | 266 | 267 | match 268 | (:) 269 | name 270 | punctuation.definition.colon.go 271 | 272 | 273 | match 274 | (\[|\]|{|}|\(|\)) 275 | name 276 | punctuation.definition.bracket.go 277 | 278 | 279 | repository 280 | 281 | string_escaped_char 282 | 283 | patterns 284 | 285 | 286 | match 287 | \\(\\|[abfnrtv'"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|[0-7]{3}) 288 | name 289 | constant.character.escape.go 290 | 291 | 292 | match 293 | \\. 294 | name 295 | invalid.illegal.unknown-escape.go 296 | 297 | 298 | 299 | string_placeholder 300 | 301 | patterns 302 | 303 | 304 | match 305 | (?x)% 306 | (\d+\$)? # field (argument #) 307 | [#0\- +']* # flags 308 | [,;:_]? # separator character (AltiVec) 309 | ((-?\d+)|\*(-?\d+\$)?)? # minimum field width 310 | (\.((-?\d+)|\*(-?\d+\$)?)?)? # precision 311 | [diouxXDOUeEfFgGaAcCsSqpnvtTbyYhHmMzZ%] # conversion type 312 | 313 | name 314 | constant.other.placeholder.go 315 | 316 | 317 | 318 | 319 | scopeName 320 | source.go 321 | uuid 322 | 1caaa75c-b61d-11e2-ba93-138feb5db969 323 | 324 | 325 | -------------------------------------------------------------------------------- /subl3/syntax/GoSublime-Go.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "Based on work from github.com/frou/GoFeather and github.com/DisposaBoy/GoSublime", 3 | "fileTypes": [ 4 | "go" 5 | ], 6 | "firstLineMatch": "-[*]-( Mode:)? Go -[*]-", 7 | "keyEquivalent": "^~G", 8 | "name": "GoSublime: Go", 9 | "patterns": [ 10 | { 11 | "begin": "/\\*", 12 | "end": "\\*/", 13 | "name": "comment.block.go" 14 | }, 15 | { 16 | "begin": "//", 17 | "end": "\\z", 18 | "name": "comment.line.double-slash.go" 19 | }, 20 | { 21 | "begin": "\"", 22 | "beginCaptures": { 23 | "0": { 24 | "name": "punctuation.definition.string.begin.go" 25 | } 26 | }, 27 | "end": "\"", 28 | "endCaptures": { 29 | "0": { 30 | "name": "punctuation.definition.string.end.go" 31 | } 32 | }, 33 | "name": "string.quoted.double.go", 34 | "patterns": [ 35 | { 36 | "include": "#string_placeholder" 37 | }, 38 | { 39 | "include": "#string_escaped_char" 40 | } 41 | ] 42 | }, 43 | { 44 | "begin": "`", 45 | "beginCaptures": { 46 | "0": { 47 | "name": "punctuation.definition.string.begin.go" 48 | } 49 | }, 50 | "end": "`", 51 | "endCaptures": { 52 | "0": { 53 | "name": "punctuation.definition.string.end.go" 54 | } 55 | }, 56 | "name": "string.quoted.raw.go", 57 | "patterns": [ 58 | { 59 | "include": "#string_placeholder" 60 | }, 61 | { 62 | "include": "source.gotemplate" 63 | } 64 | ] 65 | }, 66 | { 67 | "match": "\\b(true|false|nil|iota)\\b", 68 | "name": "constant.language.go" 69 | }, 70 | { 71 | "match": "\\b((\\d+\\.(\\d+)?([eE][+-]?\\d+)?|\\d+[eE][+-]?\\d+|\\.\\d+([eE][+-]?\\d+)?)i?)\\b", 72 | "name": "constant.numeric.floating-point.go" 73 | }, 74 | { 75 | "match": "\\b(\\d+i|0[xX][0-9A-Fa-f]+|0[0-7]*|[1-9][0-9]*)\\b", 76 | "name": "constant.numeric.integer.go" 77 | }, 78 | { 79 | "name": "constant.other.rune.go", 80 | "match": "'(?:[^'\\\\]|\\\\(?:\\\\|[abfnrtv']|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|[0-7]{3}))'" 81 | }, 82 | { 83 | "match": "\\b(bool|byte|complex(64|128)|error|float(32|64)|rune|string|u?int(8|16|32|64)?|uintptr)\\b", 84 | "name": "storage.type.go" 85 | }, 86 | { 87 | "comment": "A subset of keyword.other.go for flow control keywords.", 88 | "match": "\\b(break|case|continue|default|defer|else|for|go|goto|if|range|return|select|switch)\\b", 89 | "name": "keyword.control.go" 90 | }, 91 | { 92 | "match": "\\b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)\\b", 93 | "name": "keyword.other.go" 94 | }, 95 | { 96 | "captures": { 97 | "0": { 98 | "name": "variable.other.go" 99 | }, 100 | "1": { 101 | "name": "keyword.operator.initialize.go" 102 | } 103 | }, 104 | "comment": "This matches the 'x := 0' style of variable declaration.", 105 | "match": "(?:[[:alpha:]_][[:alnum:]_]*)(?:,\\s+[[:alpha:]_][[:alnum:]_]*)*\\s*(:=)", 106 | "name": "meta.initialization.short.go" 107 | }, 108 | { 109 | "match": "(?<=(\\Afunc|...\\))\\s)\\b(\\w+)\\b(?=\\()", 110 | "name": "entity.name.function.go" 111 | }, 112 | { 113 | "match": "(?<=(\\sfunc|....\\))\\s)\\b(\\w+)\\b(?=\\()", 114 | "name": "entity.name.function.go" 115 | }, 116 | { 117 | "match": "(?<=\\Atype\\s)\\b(\\w+)\\b", 118 | "name": "entity.name.type.go" 119 | }, 120 | { 121 | "match": "(?<=\\stype\\s)\\b(\\w+)\\b", 122 | "name": "entity.name.type.go" 123 | }, 124 | { 125 | "match": "\\b(append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)\\b", 126 | "name": "support.function.builtin.go" 127 | }, 128 | { 129 | "match": "\\b(\\w+)\\b(?=\\()", 130 | "name": "support.function.go" 131 | }, 132 | { 133 | "match": "(<-)", 134 | "name": "keyword.operator.channel.go" 135 | }, 136 | { 137 | "match": "(==|!=|<|<=|>|>=)", 138 | "name": "keyword.operator.comparison.go" 139 | }, 140 | { 141 | "match": "(&&|[|]{2}|!)", 142 | "name": "keyword.operator.logical.go" 143 | }, 144 | { 145 | "match": "([+]{2})", 146 | "name": "keyword.operator.increment.go" 147 | }, 148 | { 149 | "match": "(--)", 150 | "name": "keyword.decrement.go" 151 | }, 152 | { 153 | "match": "(=|(?:[+]|-|[|]|^|[*]|/|%|<<|>>|&|&^)=)", 154 | "name": "keyword.operator.assignment.go" 155 | }, 156 | { 157 | "match": "([+]|-|[*]|/|%|&|[|]|^|&^|<<|>>)", 158 | "name": "keyword.operator.arithmetic.go" 159 | }, 160 | { 161 | "match": "(;)", 162 | "name": "keyword.operator.semi-colon.go" 163 | }, 164 | { 165 | "match": "(,)", 166 | "name": "punctuation.definition.comma.go" 167 | }, 168 | { 169 | "match": "([.])", 170 | "name": "punctuation.definition.dot.go" 171 | }, 172 | { 173 | "match": "(:)", 174 | "name": "punctuation.definition.colon.go" 175 | }, 176 | { 177 | "match": "(\\[|\\]|{|}|\\(|\\))", 178 | "name": "punctuation.definition.bracket.go" 179 | } 180 | ], 181 | // note: keep this in sync with GoTemplate 182 | "repository": { 183 | "string_escaped_char": { 184 | "patterns": [ 185 | { 186 | // note: keep this in sync with constant.other.rune.go 187 | "match": "\\\\(\\\\|[abfnrtv'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|[0-7]{3})", 188 | "name": "constant.character.escape.go" 189 | }, 190 | { 191 | "match": "\\\\.", 192 | "name": "invalid.illegal.unknown-escape.go" 193 | } 194 | ] 195 | }, 196 | "string_placeholder": { 197 | "patterns": [ 198 | { 199 | "match": "(?x)%\n (\\d+\\$)? # field (argument #)\n [#0\\- +']* # flags\n [,;:_]? # separator character (AltiVec)\n ((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n (\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n [diouxXDOUeEfFgGaAcCsSqpnvtTbyYhHmMzZ%] # conversion type\n ", 200 | "name": "constant.other.placeholder.go" 201 | } 202 | ] 203 | } 204 | }, 205 | "scopeName": "source.go", 206 | "uuid": "1caaa75c-b61d-11e2-ba93-138feb5db969" 207 | } 208 | -------------------------------------------------------------------------------- /subl3/syntax/GoSublime-HTML.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | gohtml 8 | 9 | name 10 | GoSublime: HTML 11 | patterns 12 | 13 | 14 | include 15 | text.html.basic 16 | 17 | 18 | include 19 | source.gotemplate 20 | 21 | 22 | scopeName 23 | text.html.gohtml 24 | uuid 25 | 78c486ec-0101-11e2-a85a-00262d996a67 26 | 27 | 28 | -------------------------------------------------------------------------------- /subl3/syntax/GoSublime-HTML.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GoSublime: HTML", 3 | "uuid": "78c486ec-0101-11e2-a85a-00262d996a67", 4 | "scopeName": "text.html.gohtml", 5 | "fileTypes": ["gohtml"], 6 | 7 | "patterns": [ 8 | { 9 | "include": "text.html.basic", 10 | }, 11 | { 12 | "include": "source.gotemplate", 13 | }, 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /subl3/syntax/GoSublime-Template.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | foldingStartMarker 6 | \{\{\s*(?:if|with|range)\b 7 | foldingStopMarker 8 | \{\{\s*(?:else|end)\b 9 | name 10 | GoSublime: Template 11 | patterns 12 | 13 | 14 | begin 15 | \{\{ 16 | beginCaptures 17 | 18 | 0 19 | 20 | name 21 | punctuation.section.embedded.begin.gotemplate 22 | 23 | 24 | end 25 | \}\} 26 | endCaptures 27 | 28 | 0 29 | 30 | name 31 | punctuation.section.embedded.end.gotemplate 32 | 33 | 34 | patterns 35 | 36 | 37 | match 38 | := 39 | name 40 | keyword.operator.initialize.gotemplate 41 | 42 | 43 | match 44 | \| 45 | name 46 | keyword.operator.pipe.gotemplate 47 | 48 | 49 | match 50 | [.$][\w]* 51 | name 52 | variable.other.gotemplate 53 | 54 | 55 | match 56 | \b(if|else|range|template|with|end|nil|with|define)\b 57 | name 58 | keyword.control.gotemplate 59 | 60 | 61 | match 62 | \b(and|call|html|index|js|len|not|or|print|printf|println|urlquery|eq|ne|lt|le|gt|ge)\b 63 | name 64 | support.function.builtin.gotemplate 65 | 66 | 67 | begin 68 | /\* 69 | end 70 | \*/ 71 | name 72 | comment.block.gotemplate 73 | 74 | 75 | begin 76 | " 77 | beginCaptures 78 | 79 | 0 80 | 81 | name 82 | punctuation.definition.string.begin.gotemplate 83 | 84 | 85 | end 86 | " 87 | endCaptures 88 | 89 | 0 90 | 91 | name 92 | punctuation.definition.string.end.gotemplate 93 | 94 | 95 | name 96 | string.quoted.double.gotemplate 97 | patterns 98 | 99 | 100 | include 101 | #string_placeholder 102 | 103 | 104 | include 105 | #string_escaped_char 106 | 107 | 108 | 109 | 110 | begin 111 | ` 112 | beginCaptures 113 | 114 | 0 115 | 116 | name 117 | punctuation.definition.string.begin.gotemplate 118 | 119 | 120 | end 121 | ` 122 | endCaptures 123 | 124 | 0 125 | 126 | name 127 | punctuation.definition.string.end.gotemplate 128 | 129 | 130 | name 131 | string.quoted.raw.gotemplate 132 | patterns 133 | 134 | 135 | include 136 | #string_placeholder 137 | 138 | 139 | 140 | 141 | 142 | 143 | repository 144 | 145 | string_escaped_char 146 | 147 | patterns 148 | 149 | 150 | match 151 | \\(\\|[abfnrtv'"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|[0-7]{3}) 152 | name 153 | constant.character.escape.gotemplate 154 | 155 | 156 | match 157 | \\. 158 | name 159 | invalid.illegal.unknown-escape.gotemplate 160 | 161 | 162 | 163 | string_placeholder 164 | 165 | patterns 166 | 167 | 168 | match 169 | (?x)% 170 | (\d+\$)? # field (argument #) 171 | [#0\- +']* # flags 172 | [,;:_]? # separator character (AltiVec) 173 | ((-?\d+)|\*(-?\d+\$)?)? # minimum field width 174 | (\.((-?\d+)|\*(-?\d+\$)?)?)? # precision 175 | [diouxXDOUeEfFgGaAcCsSqpnvtTbyYhHmMzZ%] # conversion type 176 | 177 | name 178 | constant.other.placeholder.gotemplate 179 | 180 | 181 | match 182 | % 183 | name 184 | invalid.illegal.placeholder.gotemplate 185 | 186 | 187 | 188 | 189 | scopeName 190 | source.gotemplate 191 | uuid 192 | 43606de8-c638-11e2-b661-6711676f99ca 193 | 194 | 195 | -------------------------------------------------------------------------------- /subl3/syntax/GoSublime-Template.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GoSublime: Template", 3 | "uuid": "43606de8-c638-11e2-b661-6711676f99ca", 4 | "scopeName": "source.gotemplate", 5 | 6 | "foldingStartMarker": "\\{\\{\\s*(?:if|with|range)\\b", 7 | "foldingStopMarker": "\\{\\{\\s*(?:else|end)\\b", 8 | 9 | "patterns": [ 10 | { 11 | "begin": "\\{\\{", 12 | "beginCaptures": { 13 | "0": { 14 | "name": "punctuation.section.embedded.begin.gotemplate" 15 | } 16 | }, 17 | 18 | "end": "\\}\\}", 19 | "endCaptures": { 20 | "0": { 21 | "name": "punctuation.section.embedded.end.gotemplate" 22 | } 23 | }, 24 | 25 | "patterns": [ 26 | { 27 | "match": ":=", 28 | "name": "keyword.operator.initialize.gotemplate" 29 | }, 30 | { 31 | "match": "\\|", 32 | "name": "keyword.operator.pipe.gotemplate" 33 | }, 34 | { 35 | "match": "[.$][\\w]*", 36 | "name": "variable.other.gotemplate" 37 | }, 38 | { 39 | "match": "\\b(if|else|range|template|with|end|nil|with|define)\\b", 40 | "name": "keyword.control.gotemplate" 41 | }, 42 | { 43 | "match": "\\b(and|call|html|index|js|len|not|or|print|printf|println|urlquery|eq|ne|lt|le|gt|ge)\\b", 44 | "name": "support.function.builtin.gotemplate" 45 | }, 46 | { 47 | "begin": "/\\*", 48 | "end": "\\*/", 49 | "name": "comment.block.gotemplate" 50 | }, 51 | { 52 | "begin": "\"", 53 | "beginCaptures": { 54 | "0": { 55 | "name": "punctuation.definition.string.begin.gotemplate" 56 | } 57 | }, 58 | "end": "\"", 59 | "endCaptures": { 60 | "0": { 61 | "name": "punctuation.definition.string.end.gotemplate" 62 | } 63 | }, 64 | "name": "string.quoted.double.gotemplate", 65 | "patterns": [ 66 | { 67 | "include": "#string_placeholder" 68 | }, 69 | { 70 | "include": "#string_escaped_char" 71 | } 72 | ] 73 | }, 74 | { 75 | "begin": "`", 76 | "beginCaptures": { 77 | "0": { 78 | "name": "punctuation.definition.string.begin.gotemplate" 79 | } 80 | }, 81 | "end": "`", 82 | "endCaptures": { 83 | "0": { 84 | "name": "punctuation.definition.string.end.gotemplate" 85 | } 86 | }, 87 | "name": "string.quoted.raw.gotemplate", 88 | "patterns": [ 89 | { 90 | "include": "#string_placeholder" 91 | } 92 | ] 93 | } 94 | ], 95 | } 96 | ], 97 | "repository": { 98 | "string_escaped_char": { 99 | "patterns": [ 100 | { 101 | // note: keep this in sync with constant.other.rune.go 102 | "match": "\\\\(\\\\|[abfnrtv'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|[0-7]{3})", 103 | "name": "constant.character.escape.gotemplate" 104 | }, 105 | { 106 | "match": "\\\\.", 107 | "name": "invalid.illegal.unknown-escape.gotemplate" 108 | } 109 | ] 110 | }, 111 | "string_placeholder": { 112 | "patterns": [ 113 | { 114 | "match": "(?x)%\n (\\d+\\$)? # field (argument #)\n [#0\\- +']* # flags\n [,;:_]? # separator character (AltiVec)\n ((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n (\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n [diouxXDOUeEfFgGaAcCsSqpnvtTbyYhHmMzZ%] # conversion type\n ", 115 | "name": "constant.other.placeholder.gotemplate" 116 | }, 117 | { 118 | "match": "%", 119 | "name": "invalid.illegal.placeholder.gotemplate" 120 | } 121 | ] 122 | } 123 | }, 124 | } 125 | -------------------------------------------------------------------------------- /subl3/syntax/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The GoSublime Authors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /type_alias_build_hack_18.go: -------------------------------------------------------------------------------- 1 | // +build !go1.9,!go1.8.typealias 2 | 3 | package main 4 | 5 | import ( 6 | "go/ast" 7 | ) 8 | 9 | func typeAliasSpec(name string, typ ast.Expr) *ast.TypeSpec { 10 | return &ast.TypeSpec{ 11 | Name: ast.NewIdent(name), 12 | Type: typ, 13 | } 14 | } 15 | 16 | func isAliasTypeSpec(t *ast.TypeSpec) bool { 17 | return false 18 | } 19 | -------------------------------------------------------------------------------- /type_alias_build_hack_19.go: -------------------------------------------------------------------------------- 1 | // +build go1.9 go1.8.typealias 2 | 3 | package main 4 | 5 | import ( 6 | "go/ast" 7 | ) 8 | 9 | func typeAliasSpec(name string, typ ast.Expr) *ast.TypeSpec { 10 | return &ast.TypeSpec{ 11 | Name: ast.NewIdent(name), 12 | Assign: 1, 13 | Type: typ, 14 | } 15 | } 16 | 17 | func isAliasTypeSpec(t *ast.TypeSpec) bool { 18 | return t.Assign != 0 19 | } 20 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/build" 7 | "io/ioutil" 8 | "os" 9 | "path/filepath" 10 | "runtime" 11 | "strings" 12 | "sync" 13 | "unicode/utf8" 14 | ) 15 | 16 | // our own readdir, which skips the files it cannot lstat 17 | func readdir_lstat(name string) ([]os.FileInfo, error) { 18 | f, err := os.Open(name) 19 | if err != nil { 20 | return nil, err 21 | } 22 | defer f.Close() 23 | 24 | names, err := f.Readdirnames(-1) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | out := make([]os.FileInfo, 0, len(names)) 30 | for _, lname := range names { 31 | s, err := os.Lstat(filepath.Join(name, lname)) 32 | if err != nil { 33 | continue 34 | } 35 | out = append(out, s) 36 | } 37 | return out, nil 38 | } 39 | 40 | // our other readdir function, only opens and reads 41 | func readdir(dirname string) []os.FileInfo { 42 | f, err := os.Open(dirname) 43 | if err != nil { 44 | return nil 45 | } 46 | fi, err := f.Readdir(-1) 47 | f.Close() 48 | if err != nil { 49 | panic(err) 50 | } 51 | return fi 52 | } 53 | 54 | // returns truncated 'data' and amount of bytes skipped (for cursor pos adjustment) 55 | func filter_out_shebang(data []byte) ([]byte, int) { 56 | if len(data) > 2 && data[0] == '#' && data[1] == '!' { 57 | newline := bytes.Index(data, []byte("\n")) 58 | if newline != -1 && len(data) > newline+1 { 59 | return data[newline+1:], newline + 1 60 | } 61 | } 62 | return data, 0 63 | } 64 | 65 | func file_exists(filename string) bool { 66 | _, err := os.Stat(filename) 67 | if err != nil { 68 | return false 69 | } 70 | return true 71 | } 72 | 73 | func is_dir(path string) bool { 74 | fi, err := os.Stat(path) 75 | return err == nil && fi.IsDir() 76 | } 77 | 78 | func char_to_byte_offset(s []byte, offset_c int) (offset_b int) { 79 | for offset_b = 0; offset_c > 0 && offset_b < len(s); offset_b++ { 80 | if utf8.RuneStart(s[offset_b]) { 81 | offset_c-- 82 | } 83 | } 84 | return offset_b 85 | } 86 | 87 | func xdg_home_dir() string { 88 | xdghome := os.Getenv("XDG_CONFIG_HOME") 89 | if xdghome == "" { 90 | xdghome = filepath.Join(os.Getenv("HOME"), ".config") 91 | } 92 | return xdghome 93 | } 94 | 95 | func has_prefix(s, prefix string, ignorecase bool) bool { 96 | if ignorecase { 97 | s = strings.ToLower(s) 98 | prefix = strings.ToLower(prefix) 99 | } 100 | return strings.HasPrefix(s, prefix) 101 | } 102 | 103 | func find_bzl_project_root(libpath, path string) (string, error) { 104 | if libpath == "" { 105 | return "", fmt.Errorf("could not find project root, libpath is empty") 106 | } 107 | 108 | pathMap := map[string]struct{}{} 109 | for _, lp := range strings.Split(libpath, ":") { 110 | lp := strings.TrimSpace(lp) 111 | pathMap[filepath.Clean(lp)] = struct{}{} 112 | } 113 | 114 | path = filepath.Dir(path) 115 | if path == "" { 116 | return "", fmt.Errorf("project root is blank") 117 | } 118 | 119 | start := path 120 | for path != "/" { 121 | if _, ok := pathMap[filepath.Clean(path)]; ok { 122 | return path, nil 123 | } 124 | path = filepath.Dir(path) 125 | } 126 | return "", fmt.Errorf("could not find project root in %q or its parents", start) 127 | } 128 | 129 | // Code taken directly from `gb`, I hope author doesn't mind. 130 | func find_gb_project_root(path string) (string, error) { 131 | path = filepath.Dir(path) 132 | if path == "" { 133 | return "", fmt.Errorf("project root is blank") 134 | } 135 | start := path 136 | for path != "/" { 137 | root := filepath.Join(path, "src") 138 | if _, err := os.Stat(root); err != nil { 139 | if os.IsNotExist(err) { 140 | path = filepath.Dir(path) 141 | continue 142 | } 143 | return "", err 144 | } 145 | path, err := filepath.EvalSymlinks(path) 146 | if err != nil { 147 | return "", err 148 | } 149 | return path, nil 150 | } 151 | return "", fmt.Errorf("could not find project root in %q or its parents", start) 152 | } 153 | 154 | // vendorlessImportPath returns the devendorized version of the provided import path. 155 | // e.g. "foo/bar/vendor/a/b" => "a/b" 156 | func vendorlessImportPath(ipath string, currentPackagePath string) (string, bool) { 157 | split := strings.Split(ipath, "vendor/") 158 | // no vendor in path 159 | if len(split) == 1 { 160 | return ipath, true 161 | } 162 | // this import path does not belong to the current package 163 | if currentPackagePath != "" && !strings.Contains(currentPackagePath, split[0]) { 164 | return "", false 165 | } 166 | // Devendorize for use in import statement. 167 | if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { 168 | return ipath[i+len("/vendor/"):], true 169 | } 170 | if strings.HasPrefix(ipath, "vendor/") { 171 | return ipath[len("vendor/"):], true 172 | } 173 | return ipath, true 174 | } 175 | 176 | //------------------------------------------------------------------------- 177 | // print_backtrace 178 | // 179 | // a nicer backtrace printer than the default one 180 | //------------------------------------------------------------------------- 181 | 182 | var g_backtrace_mutex sync.Mutex 183 | 184 | func print_backtrace(err interface{}) { 185 | g_backtrace_mutex.Lock() 186 | defer g_backtrace_mutex.Unlock() 187 | fmt.Printf("panic: %v\n", err) 188 | i := 2 189 | for { 190 | pc, file, line, ok := runtime.Caller(i) 191 | if !ok { 192 | break 193 | } 194 | f := runtime.FuncForPC(pc) 195 | fmt.Printf("%d(%s): %s:%d\n", i-1, f.Name(), file, line) 196 | i++ 197 | } 198 | fmt.Println("") 199 | } 200 | 201 | //------------------------------------------------------------------------- 202 | // File reader goroutine 203 | // 204 | // It's a bad idea to block multiple goroutines on file I/O. Creates many 205 | // threads which fight for HDD. Therefore only single goroutine should read HDD 206 | // at the same time. 207 | //------------------------------------------------------------------------- 208 | 209 | type file_read_request struct { 210 | filename string 211 | out chan file_read_response 212 | } 213 | 214 | type file_read_response struct { 215 | data []byte 216 | error error 217 | } 218 | 219 | type file_reader_type struct { 220 | in chan file_read_request 221 | } 222 | 223 | func new_file_reader() *file_reader_type { 224 | this := new(file_reader_type) 225 | this.in = make(chan file_read_request) 226 | go func() { 227 | var rsp file_read_response 228 | for { 229 | req := <-this.in 230 | rsp.data, rsp.error = ioutil.ReadFile(req.filename) 231 | req.out <- rsp 232 | } 233 | }() 234 | return this 235 | } 236 | 237 | func (this *file_reader_type) read_file(filename string) ([]byte, error) { 238 | req := file_read_request{ 239 | filename, 240 | make(chan file_read_response), 241 | } 242 | this.in <- req 243 | rsp := <-req.out 244 | return rsp.data, rsp.error 245 | } 246 | 247 | var file_reader = new_file_reader() 248 | 249 | //------------------------------------------------------------------------- 250 | // copy of the build.Context without func fields 251 | //------------------------------------------------------------------------- 252 | 253 | type go_build_context struct { 254 | GOARCH string 255 | GOOS string 256 | GOROOT string 257 | GOPATH string 258 | CgoEnabled bool 259 | UseAllFiles bool 260 | Compiler string 261 | BuildTags []string 262 | ReleaseTags []string 263 | InstallSuffix string 264 | } 265 | 266 | func pack_build_context(ctx *build.Context) go_build_context { 267 | return go_build_context{ 268 | GOARCH: ctx.GOARCH, 269 | GOOS: ctx.GOOS, 270 | GOROOT: ctx.GOROOT, 271 | GOPATH: ctx.GOPATH, 272 | CgoEnabled: ctx.CgoEnabled, 273 | UseAllFiles: ctx.UseAllFiles, 274 | Compiler: ctx.Compiler, 275 | BuildTags: ctx.BuildTags, 276 | ReleaseTags: ctx.ReleaseTags, 277 | InstallSuffix: ctx.InstallSuffix, 278 | } 279 | } 280 | 281 | func unpack_build_context(ctx *go_build_context) package_lookup_context { 282 | return package_lookup_context{ 283 | Context: build.Context{ 284 | GOARCH: ctx.GOARCH, 285 | GOOS: ctx.GOOS, 286 | GOROOT: ctx.GOROOT, 287 | GOPATH: ctx.GOPATH, 288 | CgoEnabled: ctx.CgoEnabled, 289 | UseAllFiles: ctx.UseAllFiles, 290 | Compiler: ctx.Compiler, 291 | BuildTags: ctx.BuildTags, 292 | ReleaseTags: ctx.ReleaseTags, 293 | InstallSuffix: ctx.InstallSuffix, 294 | }, 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /vim/autoload/gocomplete.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_gocode') 2 | finish 3 | endif 4 | let g:loaded_gocode = 1 5 | 6 | fu! s:gocodeCurrentBuffer() 7 | let buf = getline(1, '$') 8 | if &encoding != 'utf-8' 9 | let buf = map(buf, 'iconv(v:val, &encoding, "utf-8")') 10 | endif 11 | if &l:fileformat == 'dos' 12 | " XXX: line2byte() depend on 'fileformat' option. 13 | " so if fileformat is 'dos', 'buf' must include '\r'. 14 | let buf = map(buf, 'v:val."\r"') 15 | endif 16 | let file = tempname() 17 | call writefile(buf, file) 18 | return file 19 | endf 20 | 21 | let s:vim_system = get(g:, 'gocomplete#system_function', 'system') 22 | 23 | fu! s:system(str, ...) 24 | return call(s:vim_system, [a:str] + a:000) 25 | endf 26 | 27 | fu! s:gocodeShellescape(arg) 28 | try 29 | let ssl_save = &shellslash 30 | set noshellslash 31 | return shellescape(a:arg) 32 | finally 33 | let &shellslash = ssl_save 34 | endtry 35 | endf 36 | 37 | fu! s:gocodeCommand(cmd, preargs, args) 38 | for i in range(0, len(a:args) - 1) 39 | let a:args[i] = s:gocodeShellescape(a:args[i]) 40 | endfor 41 | for i in range(0, len(a:preargs) - 1) 42 | let a:preargs[i] = s:gocodeShellescape(a:preargs[i]) 43 | endfor 44 | let result = s:system(printf('gocode %s %s %s', join(a:preargs), a:cmd, join(a:args))) 45 | if v:shell_error != 0 46 | return "[\"0\", []]" 47 | else 48 | if &encoding != 'utf-8' 49 | let result = iconv(result, 'utf-8', &encoding) 50 | endif 51 | return result 52 | endif 53 | endf 54 | 55 | fu! s:gocodeCurrentBufferOpt(filename) 56 | return '-in=' . a:filename 57 | endf 58 | 59 | fu! s:gocodeCursor() 60 | if &encoding != 'utf-8' 61 | let c = col('.') 62 | let buf = line('.') == 1 ? "" : (join(getline(1, line('.')-1), "\n") . "\n") 63 | let buf .= c == 1 ? "" : getline('.')[:c-2] 64 | return printf('%d', len(iconv(buf, &encoding, "utf-8"))) 65 | endif 66 | return printf('%d', line2byte(line('.')) + (col('.')-2)) 67 | endf 68 | 69 | fu! s:gocodeAutocomplete() 70 | let filename = s:gocodeCurrentBuffer() 71 | let result = s:gocodeCommand('autocomplete', 72 | \ [s:gocodeCurrentBufferOpt(filename), '-f=vim'], 73 | \ [expand('%:p'), s:gocodeCursor()]) 74 | call delete(filename) 75 | return result 76 | endf 77 | 78 | fu! gocomplete#Complete(findstart, base) 79 | "findstart = 1 when we need to get the text length 80 | if a:findstart == 1 81 | execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete() 82 | return col('.') - g:gocomplete_completions[0] - 1 83 | "findstart = 0 when we need to return the list of completions 84 | else 85 | return g:gocomplete_completions[1] 86 | endif 87 | endf 88 | -------------------------------------------------------------------------------- /vim/ftplugin/go/gocomplete.vim: -------------------------------------------------------------------------------- 1 | setlocal omnifunc=gocomplete#Complete 2 | -------------------------------------------------------------------------------- /vim/pathogen_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p "$HOME/.vim/bundle/gocode/autoload" 3 | mkdir -p "$HOME/.vim/bundle/gocode/ftplugin/go" 4 | cp "${0%/*}/autoload/gocomplete.vim" "$HOME/.vim/bundle/gocode/autoload" 5 | cp "${0%/*}/ftplugin/go/gocomplete.vim" "$HOME/.vim/bundle/gocode/ftplugin/go" 6 | -------------------------------------------------------------------------------- /vim/symlink.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd "${0%/*}" 3 | ROOTDIR=`pwd` 4 | mkdir -p "$HOME/.vim/autoload" 5 | mkdir -p "$HOME/.vim/ftplugin/go" 6 | ln -fs "$ROOTDIR/autoload/gocomplete.vim" "$HOME/.vim/autoload/" 7 | ln -fs "$ROOTDIR/ftplugin/go/gocomplete.vim" "$HOME/.vim/ftplugin/go/" 8 | -------------------------------------------------------------------------------- /vim/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p "$HOME/.vim/autoload" 3 | mkdir -p "$HOME/.vim/ftplugin/go" 4 | cp "${0%/*}/autoload/gocomplete.vim" "$HOME/.vim/autoload" 5 | cp "${0%/*}/ftplugin/go/gocomplete.vim" "$HOME/.vim/ftplugin/go" 6 | --------------------------------------------------------------------------------