.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / completion.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/completion.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/completion.go
new file mode 100644 (file)
index 0000000..3762b7a
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lsp
+
+import (
+       "bytes"
+       "context"
+       "fmt"
+       "strings"
+
+       "golang.org/x/tools/internal/event"
+       "golang.org/x/tools/internal/lsp/debug/tag"
+       "golang.org/x/tools/internal/lsp/protocol"
+       "golang.org/x/tools/internal/lsp/source"
+       "golang.org/x/tools/internal/lsp/source/completion"
+       "golang.org/x/tools/internal/span"
+)
+
+func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
+       snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
+       defer release()
+       if !ok {
+               return nil, err
+       }
+       var candidates []completion.CompletionItem
+       var surrounding *completion.Selection
+       switch fh.Kind() {
+       case source.Go:
+               candidates, surrounding, err = completion.Completion(ctx, snapshot, fh, params.Position, params.Context)
+       case source.Mod:
+               candidates, surrounding = nil, nil
+       }
+       if err != nil {
+               event.Error(ctx, "no completions found", err, tag.Position.Of(params.Position))
+       }
+       if candidates == nil {
+               return &protocol.CompletionList{
+                       IsIncomplete: true,
+                       Items:        []protocol.CompletionItem{},
+               }, nil
+       }
+       // We might need to adjust the position to account for the prefix.
+       rng, err := surrounding.Range()
+       if err != nil {
+               return nil, err
+       }
+
+       // internal/span treats end of file as the beginning of the next line, even
+       // when it's not newline-terminated. We correct for that behaviour here if
+       // end of file is not newline-terminated. See golang/go#41029.
+       src, err := fh.Read()
+       if err != nil {
+               return nil, err
+       }
+       numLines := len(bytes.Split(src, []byte("\n")))
+       tok := snapshot.FileSet().File(surrounding.Start())
+       eof := tok.Pos(tok.Size())
+
+       // For newline-terminated files, the line count reported by go/token should
+       // be lower than the actual number of lines we see when splitting by \n. If
+       // they're the same, the file isn't newline-terminated.
+       if tok.Size() > 0 && tok.LineCount() == numLines {
+               // Get the span for the last character in the file-1. This is
+               // technically incorrect, but will get span to point to the previous
+               // line.
+               spn, err := span.NewRange(snapshot.FileSet(), eof-1, eof-1).Span()
+               if err != nil {
+                       return nil, err
+               }
+               m := &protocol.ColumnMapper{
+                       URI:       fh.URI(),
+                       Converter: span.NewContentConverter(fh.URI().Filename(), src),
+                       Content:   src,
+               }
+               eofRng, err := m.Range(spn)
+               if err != nil {
+                       return nil, err
+               }
+               // Instead of using the computed range, correct for our earlier
+               // position adjustment by adding 1 to the column, not the line number.
+               pos := protocol.Position{
+                       Line:      eofRng.Start.Line,
+                       Character: eofRng.Start.Character + 1,
+               }
+               if surrounding.Start() >= eof {
+                       rng.Start = pos
+               }
+               if surrounding.End() >= eof {
+                       rng.End = pos
+               }
+       }
+
+       // When using deep completions/fuzzy matching, report results as incomplete so
+       // client fetches updated completions after every key stroke.
+       options := snapshot.View().Options()
+       incompleteResults := options.DeepCompletion || options.Matcher == source.Fuzzy
+
+       items := toProtocolCompletionItems(candidates, rng, options)
+
+       return &protocol.CompletionList{
+               IsIncomplete: incompleteResults,
+               Items:        items,
+       }, nil
+}
+
+func toProtocolCompletionItems(candidates []completion.CompletionItem, rng protocol.Range, options *source.Options) []protocol.CompletionItem {
+       var (
+               items                  = make([]protocol.CompletionItem, 0, len(candidates))
+               numDeepCompletionsSeen int
+       )
+       for i, candidate := range candidates {
+               // Limit the number of deep completions to not overwhelm the user in cases
+               // with dozens of deep completion matches.
+               if candidate.Depth > 0 {
+                       if !options.DeepCompletion {
+                               continue
+                       }
+                       if numDeepCompletionsSeen >= completion.MaxDeepCompletions {
+                               continue
+                       }
+                       numDeepCompletionsSeen++
+               }
+               insertText := candidate.InsertText
+               if options.InsertTextFormat == protocol.SnippetTextFormat {
+                       insertText = candidate.Snippet()
+               }
+
+               // This can happen if the client has snippets disabled but the
+               // candidate only supports snippet insertion.
+               if insertText == "" {
+                       continue
+               }
+
+               item := protocol.CompletionItem{
+                       Label:  candidate.Label,
+                       Detail: candidate.Detail,
+                       Kind:   candidate.Kind,
+                       TextEdit: &protocol.TextEdit{
+                               NewText: insertText,
+                               Range:   rng,
+                       },
+                       InsertTextFormat:    options.InsertTextFormat,
+                       AdditionalTextEdits: candidate.AdditionalTextEdits,
+                       // This is a hack so that the client sorts completion results in the order
+                       // according to their score. This can be removed upon the resolution of
+                       // https://github.com/Microsoft/language-server-protocol/issues/348.
+                       SortText: fmt.Sprintf("%05d", i),
+
+                       // Trim operators (VSCode doesn't like weird characters in
+                       // filterText).
+                       FilterText: strings.TrimLeft(candidate.InsertText, "&*"),
+
+                       Preselect:     i == 0,
+                       Documentation: candidate.Documentation,
+               }
+               items = append(items, item)
+       }
+       return items
+}