Skip to content

Commit e0fe9d6

Browse files
authored
Merge pull request #1012 from krzyzanowskim/marcin/semantictokentypes
Refactor SemanticTokenTypes, SemanticTokenModifiers
2 parents 64d73f4 + 79ca4c0 commit e0fe9d6

File tree

9 files changed

+185
-159
lines changed

9 files changed

+185
-159
lines changed

Sources/LanguageServerProtocol/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ add_library(LanguageServerProtocol STATIC
116116
SupportTypes/PositionEncoding.swift
117117
SupportTypes/ProgressToken.swift
118118
SupportTypes/RegistrationOptions.swift
119+
SupportTypes/SemanticTokenModifiers.swift
119120
SupportTypes/SemanticTokens.swift
121+
SupportTypes/SemanticTokenTypes.swift
120122
SupportTypes/ServerCapabilities.swift
121123
SupportTypes/SKCompletionOptions.swift
122124
SupportTypes/StringOrMarkupContent.swift
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
15+
/// Additional metadata about a token.
16+
///
17+
/// Similar to `SemanticTokenTypes`, the bit indices should
18+
/// be numbered starting at 0.
19+
public struct SemanticTokenModifiers: OptionSet, Hashable {
20+
public let rawValue: UInt32
21+
22+
public init(rawValue: UInt32) {
23+
self.rawValue = rawValue
24+
}
25+
26+
public static let declaration = Self(rawValue: 1 << 0)
27+
public static let definition = Self(rawValue: 1 << 1)
28+
public static let readonly = Self(rawValue: 1 << 2)
29+
public static let `static` = Self(rawValue: 1 << 3)
30+
public static let deprecated = Self(rawValue: 1 << 4)
31+
public static let abstract = Self(rawValue: 1 << 5)
32+
public static let async = Self(rawValue: 1 << 6)
33+
public static let modification = Self(rawValue: 1 << 7)
34+
public static let documentation = Self(rawValue: 1 << 8)
35+
public static let defaultLibrary = Self(rawValue: 1 << 9)
36+
37+
public var name: String? {
38+
switch self {
39+
case .declaration: return "declaration"
40+
case .definition: return "definition"
41+
case .readonly: return "readonly"
42+
case .static: return "static"
43+
case .deprecated: return "deprecated"
44+
case .abstract: return "abstract"
45+
case .async: return "async"
46+
case .modification: return "modification"
47+
case .documentation: return "documentation"
48+
case .defaultLibrary: return "defaultLibrary"
49+
default: return nil
50+
}
51+
}
52+
53+
/// All available modifiers, in ascending order of the bit index
54+
/// they are represented with (starting at the rightmost bit).
55+
public static let predefined: [Self] = [
56+
.declaration,
57+
.definition,
58+
.readonly,
59+
.static,
60+
.deprecated,
61+
.abstract,
62+
.async,
63+
.modification,
64+
.documentation,
65+
.defaultLibrary,
66+
]
67+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
15+
/// The predefined token type values
16+
///
17+
/// The protocol defines a set of token types and modifiers but clients are
18+
/// allowed to extend these and announce the values they support in the
19+
/// corresponding client capability.
20+
public struct SemanticTokenTypes: Hashable {
21+
public let name: String
22+
public init(_ name: String) {
23+
self.name = name
24+
}
25+
26+
public static let namespace = Self("namespace")
27+
/// Represents a generic type. Acts as a fallback for types which
28+
/// can't be mapped to a specific type like class or enum.
29+
public static let type = Self("type")
30+
public static let `class` = Self("class")
31+
public static let `enum` = Self("enum")
32+
public static let interface = Self("interface")
33+
public static let `struct` = Self("struct")
34+
public static let typeParameter = Self("typeParameter")
35+
public static let parameter = Self("parameter")
36+
public static let variable = Self("variable")
37+
public static let property = Self("property")
38+
public static let enumMember = Self("enumMember")
39+
public static let event = Self("event")
40+
public static let function = Self("function")
41+
public static let method = Self("method")
42+
public static let macro = Self("macro")
43+
public static let keyword = Self("keyword")
44+
public static let modifier = Self("modifier")
45+
public static let comment = Self("comment")
46+
public static let string = Self("string")
47+
public static let number = Self("number")
48+
public static let regexp = Self("regexp")
49+
public static let `operator` = Self("operator")
50+
/// since 3.17.0
51+
public static let decorator = Self("decorator")
52+
53+
public static var predefined: [Self] = [
54+
.namespace,
55+
.type,
56+
.class,
57+
.enum,
58+
.interface,
59+
.struct,
60+
.typeParameter,
61+
.parameter,
62+
.variable,
63+
.property,
64+
.enumMember,
65+
.event,
66+
.function,
67+
.method,
68+
.macro,
69+
.keyword,
70+
.modifier,
71+
.comment,
72+
.string,
73+
.number,
74+
.regexp,
75+
.operator,
76+
]
77+
}

Sources/SKTestSupport/Array+SyntaxHighlightingToken.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ extension Array where Element == SyntaxHighlightingToken {
3737
current.utf16index = charDelta
3838
}
3939

40-
guard let kind = SyntaxHighlightingToken.Kind(rawValue: rawKind) else { continue }
41-
let modifiers = SyntaxHighlightingToken.Modifiers(rawValue: rawModifiers)
40+
let kind = SemanticTokenTypes.all[Int(rawKind)]
41+
let modifiers = SemanticTokenModifiers(rawValue: rawModifiers)
4242

4343
append(
4444
SyntaxHighlightingToken(

Sources/SourceKitLSP/Swift/SemanticTokens.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ extension SyntaxClassifiedRange {
129129
}
130130

131131
extension SyntaxClassification {
132-
fileprivate var highlightingKindAndModifiers: (SyntaxHighlightingToken.Kind, SyntaxHighlightingToken.Modifiers)? {
132+
fileprivate var highlightingKindAndModifiers: (SemanticTokenTypes, SemanticTokenModifiers)? {
133133
switch self {
134134
case .none:
135135
return nil

Sources/SourceKitLSP/Swift/SwiftLanguageServer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ extension SwiftLanguageServer {
231231
),
232232
semanticTokensProvider: SemanticTokensOptions(
233233
legend: SemanticTokensLegend(
234-
tokenTypes: SyntaxHighlightingToken.Kind.allCases.map(\.lspName),
235-
tokenModifiers: SyntaxHighlightingToken.Modifiers.allModifiers.map { $0.lspName! }
234+
tokenTypes: SemanticTokenTypes.all.map(\.name),
235+
tokenModifiers: SemanticTokenModifiers.all.compactMap(\.name)
236236
),
237237
range: .bool(true),
238238
full: .bool(true)

Sources/SourceKitLSP/Swift/SyntaxHighlightingToken.swift

Lines changed: 26 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ public struct SyntaxHighlightingToken: Hashable {
2323
}
2424
}
2525
/// The token type.
26-
public var kind: Kind
26+
public var kind: SemanticTokenTypes
2727
/// Additional metadata about the token.
28-
public var modifiers: Modifiers
28+
public var modifiers: SemanticTokenModifiers
2929

3030
/// The (inclusive) start position of the token.
3131
public var start: Position { range.lowerBound }
@@ -34,159 +34,18 @@ public struct SyntaxHighlightingToken: Hashable {
3434
/// The length of the token in UTF-16 code units.
3535
public var utf16length: Int { end.utf16index - start.utf16index }
3636

37-
public init(range: Range<Position>, kind: Kind, modifiers: Modifiers = []) {
37+
public init(range: Range<Position>, kind: SemanticTokenTypes, modifiers: SemanticTokenModifiers = []) {
3838
assert(range.lowerBound.line == range.upperBound.line)
3939

4040
self.range = range
4141
self.kind = kind
4242
self.modifiers = modifiers
4343
}
4444

45-
public init(start: Position, utf16length: Int, kind: Kind, modifiers: Modifiers = []) {
45+
public init(start: Position, utf16length: Int, kind: SemanticTokenTypes, modifiers: SemanticTokenModifiers = []) {
4646
let range = start..<Position(line: start.line, utf16index: start.utf16index + utf16length)
4747
self.init(range: range, kind: kind, modifiers: modifiers)
4848
}
49-
50-
/// The token type.
51-
///
52-
/// Represented using an int to make the conversion to
53-
/// LSP tokens efficient. The order of this enum does not have to be
54-
/// stable, since we provide a `SemanticTokensLegend` during initialization.
55-
/// It is, however, important that the values are numbered from 0 due to
56-
/// the way the kinds are encoded in LSP.
57-
/// Also note that we intentionally use an enum here instead of e.g. a
58-
/// `RawRepresentable` struct, since we want to have a conversion to
59-
/// strings for known kinds and since these kinds are only provided by the
60-
/// server, i.e. there is no need to handle cases where unknown kinds
61-
/// have to be decoded.
62-
public enum Kind: UInt32, CaseIterable, Hashable {
63-
case namespace = 0
64-
case type
65-
case actor
66-
case `class`
67-
case `enum`
68-
case interface
69-
case `struct`
70-
case typeParameter
71-
case parameter
72-
case variable
73-
case property
74-
case enumMember
75-
case event
76-
case function
77-
case method
78-
case macro
79-
case keyword
80-
case modifier
81-
case comment
82-
case string
83-
case number
84-
case regexp
85-
case `operator`
86-
case decorator
87-
/// **(LSP Extension)**
88-
case identifier
89-
90-
/// The name of the token type used by LSP.
91-
var lspName: String {
92-
switch self {
93-
case .namespace: return "namespace"
94-
case .type: return "type"
95-
case .actor: return "class" // LSP doesn’t know about actors. Display actors as classes.
96-
case .class: return "class"
97-
case .enum: return "enum"
98-
case .interface: return "interface"
99-
case .struct: return "struct"
100-
case .typeParameter: return "typeParameter"
101-
case .parameter: return "parameter"
102-
case .variable: return "variable"
103-
case .property: return "property"
104-
case .enumMember: return "enumMember"
105-
case .event: return "event"
106-
case .function: return "function"
107-
case .method: return "method"
108-
case .macro: return "macro"
109-
case .keyword: return "keyword"
110-
case .modifier: return "modifier"
111-
case .comment: return "comment"
112-
case .string: return "string"
113-
case .number: return "number"
114-
case .regexp: return "regexp"
115-
case .operator: return "operator"
116-
case .decorator: return "decorator"
117-
case .identifier: return "identifier"
118-
}
119-
}
120-
121-
/// **Public for testing**
122-
public var _lspName: String {
123-
lspName
124-
}
125-
}
126-
127-
/// Additional metadata about a token.
128-
///
129-
/// Similar to `Kind`, the raw values do not actually have
130-
/// to be stable, do note however that the bit indices should
131-
/// be numbered starting at 0 and that the ordering should
132-
/// correspond to `allModifiers`.
133-
public struct Modifiers: OptionSet, Hashable {
134-
public static let declaration = Self(rawValue: 1 << 0)
135-
public static let definition = Self(rawValue: 1 << 1)
136-
public static let readonly = Self(rawValue: 1 << 2)
137-
public static let `static` = Self(rawValue: 1 << 3)
138-
public static let deprecated = Self(rawValue: 1 << 4)
139-
public static let abstract = Self(rawValue: 1 << 5)
140-
public static let async = Self(rawValue: 1 << 6)
141-
public static let modification = Self(rawValue: 1 << 7)
142-
public static let documentation = Self(rawValue: 1 << 8)
143-
public static let defaultLibrary = Self(rawValue: 1 << 9)
144-
145-
/// All available modifiers, in ascending order of the bit index
146-
/// they are represented with (starting at the rightmost bit).
147-
public static let allModifiers: [Self] = [
148-
.declaration,
149-
.definition,
150-
.readonly,
151-
.static,
152-
.deprecated,
153-
.abstract,
154-
.async,
155-
.modification,
156-
.documentation,
157-
.defaultLibrary,
158-
]
159-
160-
public let rawValue: UInt32
161-
162-
/// The name of the modifier used by LSP, if this
163-
/// is a single modifier. Note that every modifier
164-
/// in `allModifiers` must have an associated `lspName`.
165-
var lspName: String? {
166-
switch self {
167-
case .declaration: return "declaration"
168-
case .definition: return "definition"
169-
case .readonly: return "readonly"
170-
case .static: return "static"
171-
case .deprecated: return "deprecated"
172-
case .abstract: return "abstract"
173-
case .async: return "async"
174-
case .modification: return "modification"
175-
case .documentation: return "documentation"
176-
case .defaultLibrary: return "defaultLibrary"
177-
default: return nil
178-
}
179-
}
180-
181-
/// **Public for testing**
182-
public var _lspName: String? {
183-
lspName
184-
}
185-
186-
public init(rawValue: UInt32) {
187-
self.rawValue = rawValue
188-
}
189-
}
19049
}
19150

19251
extension Array where Element == SyntaxHighlightingToken {
@@ -214,7 +73,7 @@ extension Array where Element == SyntaxHighlightingToken {
21473
UInt32(lineDelta),
21574
UInt32(charDelta),
21675
UInt32(token.utf16length),
217-
token.kind.rawValue,
76+
token.kind.tokenType,
21877
token.modifiers.rawValue,
21978
]
22079
}
@@ -230,3 +89,24 @@ extension Array where Element == SyntaxHighlightingToken {
23089
return filter { !otherRanges.contains($0.range) } + other
23190
}
23291
}
92+
93+
extension SemanticTokenTypes {
94+
/// **(LSP Extension)**
95+
public static let identifier = Self("identifier")
96+
97+
// LSP doesn’t know about actors. Display actors as classes.
98+
public static let actor = Self("class")
99+
100+
/// All tokens supported by sourcekit-lsp
101+
public static let all: [Self] = predefined + [.identifier, .actor]
102+
103+
/// Token types are looked up by index
104+
public var tokenType: UInt32 {
105+
UInt32(Self.all.firstIndex(of: self)!)
106+
}
107+
}
108+
109+
extension SemanticTokenModifiers {
110+
/// All tokens supported by sourcekit-lsp
111+
public static let all: [Self] = predefined
112+
}

0 commit comments

Comments
 (0)