File: semtok.go

package info (click to toggle)
golang-github-cue-lang-cue 0.12.0.-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 19,072 kB
  • sloc: sh: 57; makefile: 17
file content (101 lines) | stat: -rw-r--r-- 2,574 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright 2024 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.

// The semtok package provides an encoder for LSP's semantic tokens.
package semtok

import "sort"

// A Token provides the extent and semantics of a token.
type Token struct {
	Line, Start uint32
	Len         uint32
	Type        TokenType
	Modifiers   []string
}

type TokenType string

const (
	TokNamespace TokenType = "namespace"
	TokType      TokenType = "type"
	TokInterface TokenType = "interface"
	TokTypeParam TokenType = "typeParameter"
	TokParameter TokenType = "parameter"
	TokVariable  TokenType = "variable"
	TokMethod    TokenType = "method"
	TokFunction  TokenType = "function"
	TokKeyword   TokenType = "keyword"
	TokComment   TokenType = "comment"
	TokString    TokenType = "string"
	TokNumber    TokenType = "number"
	TokOperator  TokenType = "operator"
	TokMacro     TokenType = "macro" // for templates
)

// Encode returns the LSP encoding of a sequence of tokens.
// The noStrings, noNumbers options cause strings, numbers to be skipped.
// The lists of types and modifiers determines the bitfield encoding.
func Encode(
	tokens []Token,
	noStrings, noNumbers bool,
	types, modifiers []string) []uint32 {

	// binary operators, at least, will be out of order
	sort.Slice(tokens, func(i, j int) bool {
		if tokens[i].Line != tokens[j].Line {
			return tokens[i].Line < tokens[j].Line
		}
		return tokens[i].Start < tokens[j].Start
	})

	typeMap := make(map[TokenType]int)
	for i, t := range types {
		typeMap[TokenType(t)] = i
	}

	modMap := make(map[string]int)
	for i, m := range modifiers {
		modMap[m] = 1 << uint(i) // go 1.12 compatibility
	}

	// each semantic token needs five values
	// (see Integer Encoding for Tokens in the LSP spec)
	x := make([]uint32, 5*len(tokens))
	var j int
	var last Token
	for i := 0; i < len(tokens); i++ {
		item := tokens[i]
		typ, ok := typeMap[item.Type]
		if !ok {
			continue // client doesn't want typeStr
		}
		if item.Type == TokString && noStrings {
			continue
		}
		if item.Type == TokNumber && noNumbers {
			continue
		}
		if j == 0 {
			x[0] = tokens[0].Line
		} else {
			x[j] = item.Line - last.Line
		}
		x[j+1] = item.Start
		if j > 0 && x[j] == 0 {
			x[j+1] = item.Start - last.Start
		}
		x[j+2] = item.Len
		x[j+3] = uint32(typ)
		mask := 0
		for _, s := range item.Modifiers {
			// modMap[s] is 0 if the client doesn't want this modifier
			mask |= modMap[s]
		}
		x[j+4] = uint32(mask)
		j += 5
		last = item
	}
	return x[:j]
}