github.com/julianthome/gore@v0.0.0-20231109011145-b3a6bbe6fe55/complete.go (about) 1 package gore 2 3 import ( 4 "fmt" 5 "strings" 6 "unicode" 7 8 "github.com/x-motemen/gore/gocode" 9 ) 10 11 func (s *Session) completeWord(line string, pos int) (string, []string, string) { 12 if strings.HasPrefix(strings.TrimSpace(line), ":") { 13 // complete commands 14 var idx int 15 in := strings.TrimLeftFunc(line[:pos], func(c rune) bool { 16 if c == ':' || unicode.IsSpace(c) { 17 idx++ 18 return true 19 } 20 return false 21 }) 22 var cmd string 23 if tokens := strings.Fields(in); len(tokens) > 0 { 24 cmd = tokens[0] 25 } 26 27 if !strings.Contains(in, " ") { 28 pre, post := line[:idx], line[pos:] 29 var result []string 30 for _, command := range commands { 31 name := pre + fmt.Sprint(command.name) 32 if cmd == "" || command.name.matchesPrefix(cmd) { 33 if !strings.HasPrefix(post, " ") && command.arg != "" { 34 name += " " 35 } 36 result = append(result, name) 37 } 38 } 39 return "", result, post 40 } 41 42 // complete command arguments 43 for _, command := range commands { 44 if command.complete == nil || !command.name.matches(cmd) { 45 continue 46 } 47 cmdPrefix := line[:idx] + cmd + " " 48 return cmdPrefix, command.complete(s, line[len(cmdPrefix):pos]), "" 49 } 50 51 return "", nil, "" 52 } 53 54 if !gocode.Available() { 55 return "", nil, "" 56 } 57 58 if strings.TrimSpace(line[:pos]) == "" { 59 return "", []string{line[:pos] + indent}, line[pos:] 60 } 61 62 // code completion 63 pos, cands, err := s.completeCode(line, pos, true) 64 if err != nil { 65 errorf("completeCode: %s", err) 66 return "", nil, "" 67 } 68 69 return line[0:pos], cands, "" 70 } 71 72 // completeCode does code completion within the session using gocode. 73 // in and pos specifies the current input and the cursor position (0 <= pos <= len(in)) respectively. 74 // If exprMode is set to true, the completion is done as an expression (e.g. appends "(" to functions). 75 // Return value keep specifies how many characters of in should be kept and candidates are what follow in[0:keep]. 76 func (s *Session) completeCode(in string, pos int, exprMode bool) (keep int, candidates []string, err error) { 77 s.clearQuickFix() 78 79 source, err := s.source(false) 80 if err != nil { 81 return 82 } 83 84 // Kind of dirty hack :/ 85 p := strings.LastIndex(source, "}") 86 editingSource := source[0:p] + in + source[p:] 87 cursor := len(source[0:p]) + pos 88 89 result, err := gocode.Query([]byte(editingSource), cursor) 90 if err != nil { 91 return 92 } 93 94 keep = pos - result.Cursor 95 candidates = make([]string, 0, len(result.Candidates)) 96 for _, e := range result.Candidates { 97 cand := e.Name 98 if cand == printerName && e.Class == "func" { 99 continue 100 } 101 if exprMode && e.Class == "func" { 102 cand += "(" 103 } 104 candidates = append(candidates, cand) 105 } 106 107 return 108 }