golang.org/x/tools/gopls@v0.15.3/internal/protocol/semtok/semtok.go (about)

     1  // Copyright 2024 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  // The semtok package provides an encoder for LSP's semantic tokens.
     6  package semtok
     7  
     8  import "sort"
     9  
    10  // A Token provides the extent and semantics of a token.
    11  type Token struct {
    12  	Line, Start uint32
    13  	Len         uint32
    14  	Type        TokenType
    15  	Modifiers   []string
    16  }
    17  
    18  type TokenType string
    19  
    20  const (
    21  	TokNamespace TokenType = "namespace"
    22  	TokType      TokenType = "type"
    23  	TokInterface TokenType = "interface"
    24  	TokTypeParam TokenType = "typeParameter"
    25  	TokParameter TokenType = "parameter"
    26  	TokVariable  TokenType = "variable"
    27  	TokMethod    TokenType = "method"
    28  	TokFunction  TokenType = "function"
    29  	TokKeyword   TokenType = "keyword"
    30  	TokComment   TokenType = "comment"
    31  	TokString    TokenType = "string"
    32  	TokNumber    TokenType = "number"
    33  	TokOperator  TokenType = "operator"
    34  	TokMacro     TokenType = "macro" // for templates
    35  )
    36  
    37  // Encode returns the LSP encoding of a sequence of tokens.
    38  // The noStrings, noNumbers options cause strings, numbers to be skipped.
    39  // The lists of types and modifiers determines the bitfield encoding.
    40  func Encode(
    41  	tokens []Token,
    42  	noStrings, noNumbers bool,
    43  	types, modifiers []string) []uint32 {
    44  
    45  	// binary operators, at least, will be out of order
    46  	sort.Slice(tokens, func(i, j int) bool {
    47  		if tokens[i].Line != tokens[j].Line {
    48  			return tokens[i].Line < tokens[j].Line
    49  		}
    50  		return tokens[i].Start < tokens[j].Start
    51  	})
    52  
    53  	typeMap := make(map[TokenType]int)
    54  	for i, t := range types {
    55  		typeMap[TokenType(t)] = i
    56  	}
    57  
    58  	modMap := make(map[string]int)
    59  	for i, m := range modifiers {
    60  		modMap[m] = 1 << uint(i) // go 1.12 compatibility
    61  	}
    62  
    63  	// each semantic token needs five values
    64  	// (see Integer Encoding for Tokens in the LSP spec)
    65  	x := make([]uint32, 5*len(tokens))
    66  	var j int
    67  	var last Token
    68  	for i := 0; i < len(tokens); i++ {
    69  		item := tokens[i]
    70  		typ, ok := typeMap[item.Type]
    71  		if !ok {
    72  			continue // client doesn't want typeStr
    73  		}
    74  		if item.Type == TokString && noStrings {
    75  			continue
    76  		}
    77  		if item.Type == TokNumber && noNumbers {
    78  			continue
    79  		}
    80  		if j == 0 {
    81  			x[0] = tokens[0].Line
    82  		} else {
    83  			x[j] = item.Line - last.Line
    84  		}
    85  		x[j+1] = item.Start
    86  		if j > 0 && x[j] == 0 {
    87  			x[j+1] = item.Start - last.Start
    88  		}
    89  		x[j+2] = item.Len
    90  		x[j+3] = uint32(typ)
    91  		mask := 0
    92  		for _, s := range item.Modifiers {
    93  			// modMap[s] is 0 if the client doesn't want this modifier
    94  			mask |= modMap[s]
    95  		}
    96  		x[j+4] = uint32(mask)
    97  		j += 5
    98  		last = item
    99  	}
   100  	return x[:j]
   101  }