golang.org/x/tools/gopls@v0.15.3/internal/server/code_lens.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package server
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"sort"
    11  
    12  	"golang.org/x/tools/gopls/internal/file"
    13  	"golang.org/x/tools/gopls/internal/golang"
    14  	"golang.org/x/tools/gopls/internal/mod"
    15  	"golang.org/x/tools/gopls/internal/protocol"
    16  	"golang.org/x/tools/gopls/internal/protocol/command"
    17  	"golang.org/x/tools/internal/event"
    18  	"golang.org/x/tools/internal/event/tag"
    19  )
    20  
    21  func (s *server) CodeLens(ctx context.Context, params *protocol.CodeLensParams) ([]protocol.CodeLens, error) {
    22  	ctx, done := event.Start(ctx, "lsp.Server.codeLens", tag.URI.Of(params.TextDocument.URI))
    23  	defer done()
    24  
    25  	fh, snapshot, release, err := s.fileOf(ctx, params.TextDocument.URI)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	defer release()
    30  
    31  	var lenses map[command.Command]golang.LensFunc
    32  	switch snapshot.FileKind(fh) {
    33  	case file.Mod:
    34  		lenses = mod.LensFuncs()
    35  	case file.Go:
    36  		lenses = golang.LensFuncs()
    37  	default:
    38  		// Unsupported file kind for a code lens.
    39  		return nil, nil
    40  	}
    41  	var result []protocol.CodeLens
    42  	for cmd, lf := range lenses {
    43  		if !snapshot.Options().Codelenses[string(cmd)] {
    44  			continue
    45  		}
    46  		added, err := lf(ctx, snapshot, fh)
    47  		// Code lens is called on every keystroke, so we should just operate in
    48  		// a best-effort mode, ignoring errors.
    49  		if err != nil {
    50  			event.Error(ctx, fmt.Sprintf("code lens %s failed", cmd), err)
    51  			continue
    52  		}
    53  		result = append(result, added...)
    54  	}
    55  	sort.Slice(result, func(i, j int) bool {
    56  		a, b := result[i], result[j]
    57  		if cmp := protocol.CompareRange(a.Range, b.Range); cmp != 0 {
    58  			return cmp < 0
    59  		}
    60  		return a.Command.Command < b.Command.Command
    61  	})
    62  	return result, nil
    63  }