Skip to content

Commit 36e3017

Browse files
authored
Merge pull request swiftlang#298 from benlangmuir/completion-server-side-filtering1
[completion] Filter completions on the server side
2 parents 3792761 + b3383c0 commit 36e3017

File tree

14 files changed

+1018
-324
lines changed

14 files changed

+1018
-324
lines changed

Sources/LanguageServerProtocol/Requests/CompletionRequest.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -22,6 +22,8 @@
2222
/// - Parameters:
2323
/// - textDocument: The document to perform completion in.
2424
/// - position: The location to perform completion at.
25+
/// - context: Optional code-completion context.
26+
/// - sourcekitlspOptions: **(LSP Extension)** code-completion options for sourcekit-lsp.
2527
///
2628
/// - Returns: A list of completion items to complete the code at the given position.
2729
public struct CompletionRequest: TextDocumentRequest, Hashable {
@@ -34,9 +36,18 @@ public struct CompletionRequest: TextDocumentRequest, Hashable {
3436

3537
public var context: CompletionContext?
3638

37-
public init(textDocument: TextDocumentIdentifier, position: Position) {
39+
public var sourcekitlspOptions: SKCompletionOptions?
40+
41+
public init(
42+
textDocument: TextDocumentIdentifier,
43+
position: Position,
44+
context: CompletionContext? = nil,
45+
sourcekitlspOptions: SKCompletionOptions? = nil)
46+
{
3847
self.textDocument = textDocument
3948
self.position = position
49+
self.context = context
50+
self.sourcekitlspOptions = sourcekitlspOptions
4051
}
4152
}
4253

Sources/LanguageServerProtocol/SupportTypes/Position.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -56,3 +56,13 @@ extension Position: LSPAnyCodable {
5656
])
5757
}
5858
}
59+
60+
extension Position: CustomStringConvertible, CustomDebugStringConvertible {
61+
public var description: String {
62+
"\(line + 1):\(utf16index+1)"
63+
}
64+
65+
public var debugDescription: String {
66+
"Position(line: \(line), utf16index: \(utf16index))"
67+
}
68+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 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+
/// Code-completion configuration.
14+
///
15+
/// **(LSP Extension)**: This is used as part of an extension to the
16+
/// code-completion request.
17+
public struct SKCompletionOptions: Codable, Hashable {
18+
19+
/// Whether to use server-side filtering or to return all results and let the
20+
/// client handle all filtering.
21+
public var serverSideFiltering: Bool
22+
23+
/// The maximum number of completion results to return, or `nil` for unlimited.
24+
public var maxResults: Int?
25+
26+
public init(serverSideFiltering: Bool = true, maxResults: Int? = 200) {
27+
self.serverSideFiltering = serverSideFiltering
28+
self.maxResults = maxResults
29+
}
30+
}

Sources/SourceKitD/sourcekitd_uids.swift

Lines changed: 94 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -13,105 +13,120 @@
1313
import Csourcekitd
1414

1515
public struct sourcekitd_keys {
16-
public let request: sourcekitd_uid_t
16+
public let actionname: sourcekitd_uid_t
17+
public let actionuid: sourcekitd_uid_t
18+
public let annotated_decl: sourcekitd_uid_t
19+
public let associated_usrs: sourcekitd_uid_t
20+
public let bodylength: sourcekitd_uid_t
21+
public let bodyoffset: sourcekitd_uid_t
22+
public let categorizededits: sourcekitd_uid_t
23+
public let column: sourcekitd_uid_t
1724
public let compilerargs: sourcekitd_uid_t
18-
public let offset: sourcekitd_uid_t
19-
public let length: sourcekitd_uid_t
20-
public let sourcefile: sourcekitd_uid_t
21-
public let sourcetext: sourcekitd_uid_t
22-
public let results: sourcekitd_uid_t
25+
public let context: sourcekitd_uid_t
2326
public let description: sourcekitd_uid_t
24-
public let name: sourcekitd_uid_t
25-
public let kind: sourcekitd_uid_t
26-
public let notification: sourcekitd_uid_t
27-
public let fixits: sourcekitd_uid_t
28-
public let diagnostics: sourcekitd_uid_t
2927
public let diagnostic_stage: sourcekitd_uid_t
30-
public let severity: sourcekitd_uid_t
31-
public let line: sourcekitd_uid_t
32-
public let column: sourcekitd_uid_t
33-
public let endline: sourcekitd_uid_t
28+
public let diagnostics: sourcekitd_uid_t
29+
public let doc_brief: sourcekitd_uid_t
30+
public let doc_full_as_xml: sourcekitd_uid_t
31+
public let edits: sourcekitd_uid_t
3432
public let endcolumn: sourcekitd_uid_t
33+
public let endline: sourcekitd_uid_t
3534
public let filepath: sourcekitd_uid_t
36-
public let ranges: sourcekitd_uid_t
37-
public let usr: sourcekitd_uid_t
38-
public let typename: sourcekitd_uid_t
39-
public let annotated_decl: sourcekitd_uid_t
40-
public let doc_full_as_xml: sourcekitd_uid_t
41-
public let syntactic_only: sourcekitd_uid_t
42-
public let substructure: sourcekitd_uid_t
43-
public let bodyoffset: sourcekitd_uid_t
44-
public let bodylength: sourcekitd_uid_t
45-
public let syntaxmap: sourcekitd_uid_t
35+
public let fixits: sourcekitd_uid_t
36+
public let kind: sourcekitd_uid_t
37+
public let length: sourcekitd_uid_t
38+
public let line: sourcekitd_uid_t
39+
public let name: sourcekitd_uid_t
4640
public let namelength: sourcekitd_uid_t
4741
public let nameoffset: sourcekitd_uid_t
48-
public let retrieve_refactor_actions: sourcekitd_uid_t
42+
public let not_recommended: sourcekitd_uid_t
43+
public let notification: sourcekitd_uid_t
44+
public let num_bytes_to_erase: sourcekitd_uid_t
45+
public let offset: sourcekitd_uid_t
46+
public let ranges: sourcekitd_uid_t
4947
public let refactor_actions: sourcekitd_uid_t
50-
public let actionname: sourcekitd_uid_t
51-
public let actionuid: sourcekitd_uid_t
52-
public let categorizededits: sourcekitd_uid_t
53-
public let edits: sourcekitd_uid_t
48+
public let request: sourcekitd_uid_t
49+
public let results: sourcekitd_uid_t
50+
public let retrieve_refactor_actions: sourcekitd_uid_t
51+
public let severity: sourcekitd_uid_t
52+
public let sourcefile: sourcekitd_uid_t
53+
public let sourcetext: sourcekitd_uid_t
54+
public let substructure: sourcekitd_uid_t
55+
public let syntactic_only: sourcekitd_uid_t
56+
public let syntaxmap: sourcekitd_uid_t
5457
public let text: sourcekitd_uid_t
58+
public let typename: sourcekitd_uid_t
59+
public let usr: sourcekitd_uid_t
5560

56-
// Code Completion related keys.
61+
// Code Completion options.
5762
public let codecomplete_options: sourcekitd_uid_t
5863
public let codecomplete_sort_byname: sourcekitd_uid_t
59-
public let context: sourcekitd_uid_t
60-
public let doc: sourcekitd_uid_t
61-
public let not_recommended: sourcekitd_uid_t
62-
public let num_bytes_to_erase: sourcekitd_uid_t
63-
public let associated_usrs: sourcekitd_uid_t
64-
64+
public let codecomplete_filtertext: sourcekitd_uid_t
65+
public let codecomplete_requestlimit: sourcekitd_uid_t
66+
public let codecomplete_hideunderscores: sourcekitd_uid_t
67+
public let codecomplete_hidelowpriority: sourcekitd_uid_t
68+
public let codecomplete_hidebyname: sourcekitd_uid_t
69+
public let codecomplete_addinneroperators: sourcekitd_uid_t
70+
public let codecomplete_callpatternheuristics: sourcekitd_uid_t
71+
public let codecomplete_showtopnonliteralresults: sourcekitd_uid_t
6572

6673
public init(api: sourcekitd_functions_t) {
67-
request = api.uid_get_from_cstr("key.request")!
74+
actionname = api.uid_get_from_cstr("key.actionname")!
75+
actionuid = api.uid_get_from_cstr("key.actionuid")!
76+
annotated_decl = api.uid_get_from_cstr("key.annotated_decl")!
77+
associated_usrs = api.uid_get_from_cstr("key.associated_usrs")!
78+
bodylength = api.uid_get_from_cstr("key.bodylength")!
79+
bodyoffset = api.uid_get_from_cstr("key.bodyoffset")!
80+
categorizededits = api.uid_get_from_cstr("key.categorizededits")!
81+
column = api.uid_get_from_cstr("key.column")!
6882
compilerargs = api.uid_get_from_cstr("key.compilerargs")!
69-
offset = api.uid_get_from_cstr("key.offset")!
70-
length = api.uid_get_from_cstr("key.length")!
71-
sourcefile = api.uid_get_from_cstr("key.sourcefile")!
72-
sourcetext = api.uid_get_from_cstr("key.sourcetext")!
73-
results = api.uid_get_from_cstr("key.results")!
83+
context = api.uid_get_from_cstr("key.context")!
7484
description = api.uid_get_from_cstr("key.description")!
75-
name = api.uid_get_from_cstr("key.name")!
76-
kind = api.uid_get_from_cstr("key.kind")!
77-
notification = api.uid_get_from_cstr("key.notification")!
78-
fixits = api.uid_get_from_cstr("key.fixits")!
79-
diagnostics = api.uid_get_from_cstr("key.diagnostics")!
8085
diagnostic_stage = api.uid_get_from_cstr("key.diagnostic_stage")!
81-
severity = api.uid_get_from_cstr("key.severity")!
82-
line = api.uid_get_from_cstr("key.line")!
83-
column = api.uid_get_from_cstr("key.column")!
84-
endline = api.uid_get_from_cstr("key.endline")!
86+
diagnostics = api.uid_get_from_cstr("key.diagnostics")!
87+
doc_brief = api.uid_get_from_cstr("key.doc.brief")!
88+
doc_full_as_xml = api.uid_get_from_cstr("key.doc.full_as_xml")!
89+
edits = api.uid_get_from_cstr("key.edits")!
8590
endcolumn = api.uid_get_from_cstr("key.endcolumn")!
91+
endline = api.uid_get_from_cstr("key.endline")!
8692
filepath = api.uid_get_from_cstr("key.filepath")!
87-
ranges = api.uid_get_from_cstr("key.ranges")!
88-
usr = api.uid_get_from_cstr("key.usr")!
89-
typename = api.uid_get_from_cstr("key.typename")!
90-
annotated_decl = api.uid_get_from_cstr("key.annotated_decl")!
91-
doc_full_as_xml = api.uid_get_from_cstr("key.doc.full_as_xml")!
92-
syntactic_only = api.uid_get_from_cstr("key.syntactic_only")!
93-
substructure = api.uid_get_from_cstr("key.substructure")!
94-
bodyoffset = api.uid_get_from_cstr("key.bodyoffset")!
95-
bodylength = api.uid_get_from_cstr("key.bodylength")!
96-
syntaxmap = api.uid_get_from_cstr("key.syntaxmap")!
93+
fixits = api.uid_get_from_cstr("key.fixits")!
94+
kind = api.uid_get_from_cstr("key.kind")!
95+
length = api.uid_get_from_cstr("key.length")!
96+
line = api.uid_get_from_cstr("key.line")!
97+
name = api.uid_get_from_cstr("key.name")!
9798
namelength = api.uid_get_from_cstr("key.namelength")!
9899
nameoffset = api.uid_get_from_cstr("key.nameoffset")!
99-
retrieve_refactor_actions = api.uid_get_from_cstr("key.retrieve_refactor_actions")!
100+
not_recommended = api.uid_get_from_cstr("key.not_recommended")!
101+
notification = api.uid_get_from_cstr("key.notification")!
102+
num_bytes_to_erase = api.uid_get_from_cstr("key.num_bytes_to_erase")!
103+
offset = api.uid_get_from_cstr("key.offset")!
104+
ranges = api.uid_get_from_cstr("key.ranges")!
100105
refactor_actions = api.uid_get_from_cstr("key.refactor_actions")!
101-
actionname = api.uid_get_from_cstr("key.actionname")!
102-
actionuid = api.uid_get_from_cstr("key.actionuid")!
103-
categorizededits = api.uid_get_from_cstr("key.categorizededits")!
104-
edits = api.uid_get_from_cstr("key.edits")!
106+
request = api.uid_get_from_cstr("key.request")!
107+
results = api.uid_get_from_cstr("key.results")!
108+
retrieve_refactor_actions = api.uid_get_from_cstr("key.retrieve_refactor_actions")!
109+
severity = api.uid_get_from_cstr("key.severity")!
110+
sourcefile = api.uid_get_from_cstr("key.sourcefile")!
111+
sourcetext = api.uid_get_from_cstr("key.sourcetext")!
112+
substructure = api.uid_get_from_cstr("key.substructure")!
113+
syntactic_only = api.uid_get_from_cstr("key.syntactic_only")!
114+
syntaxmap = api.uid_get_from_cstr("key.syntaxmap")!
105115
text = api.uid_get_from_cstr("key.text")!
116+
typename = api.uid_get_from_cstr("key.typename")!
117+
usr = api.uid_get_from_cstr("key.usr")!
106118

107-
// Code Completion related keys.
119+
// Code Completion options
108120
codecomplete_options = api.uid_get_from_cstr("key.codecomplete.options")!
109121
codecomplete_sort_byname = api.uid_get_from_cstr("key.codecomplete.sort.byname")!
110-
context = api.uid_get_from_cstr("key.context")!
111-
doc = api.uid_get_from_cstr("key.doc.brief")!
112-
not_recommended = api.uid_get_from_cstr("key.not_recommended")!
113-
num_bytes_to_erase = api.uid_get_from_cstr("key.num_bytes_to_erase")!
114-
associated_usrs = api.uid_get_from_cstr("key.associated_usrs")!
122+
codecomplete_filtertext = api.uid_get_from_cstr("key.codecomplete.filtertext")!
123+
codecomplete_requestlimit = api.uid_get_from_cstr("key.codecomplete.requestlimit")!
124+
codecomplete_hideunderscores = api.uid_get_from_cstr("key.codecomplete.hideunderscores")!
125+
codecomplete_hidelowpriority = api.uid_get_from_cstr("key.codecomplete.hidelowpriority")!
126+
codecomplete_hidebyname = api.uid_get_from_cstr("key.codecomplete.hidebyname")!
127+
codecomplete_addinneroperators = api.uid_get_from_cstr("key.codecomplete.addinneroperators")!
128+
codecomplete_callpatternheuristics = api.uid_get_from_cstr("key.codecomplete.callpatternheuristics")!
129+
codecomplete_showtopnonliteralresults = api.uid_get_from_cstr("key.codecomplete.showtopnonliteralresults")!
115130
}
116131
}
117132

@@ -120,6 +135,9 @@ public struct sourcekitd_requests {
120135
public let editor_close: sourcekitd_uid_t
121136
public let editor_replacetext: sourcekitd_uid_t
122137
public let codecomplete: sourcekitd_uid_t
138+
public let codecomplete_open: sourcekitd_uid_t
139+
public let codecomplete_update: sourcekitd_uid_t
140+
public let codecomplete_close: sourcekitd_uid_t
123141
public let cursorinfo: sourcekitd_uid_t
124142
public let relatedidents: sourcekitd_uid_t
125143
public let semantic_refactoring: sourcekitd_uid_t
@@ -129,6 +147,9 @@ public struct sourcekitd_requests {
129147
editor_close = api.uid_get_from_cstr("source.request.editor.close")!
130148
editor_replacetext = api.uid_get_from_cstr("source.request.editor.replacetext")!
131149
codecomplete = api.uid_get_from_cstr("source.request.codecomplete")!
150+
codecomplete_open = api.uid_get_from_cstr("source.request.codecomplete.open")!
151+
codecomplete_update = api.uid_get_from_cstr("source.request.codecomplete.update")!
152+
codecomplete_close = api.uid_get_from_cstr("source.request.codecomplete.close")!
132153
cursorinfo = api.uid_get_from_cstr("source.request.cursorinfo")!
133154
relatedidents = api.uid_get_from_cstr("source.request.relatedidents")!
134155
semantic_refactoring = api.uid_get_from_cstr("source.request.semantic.refactoring")!

Sources/SourceKitLSP/SourceKitServer+Options.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import LanguageServerProtocol
1314
import SKCore
1415

1516
extension SourceKitServer {
@@ -27,10 +28,19 @@ extension SourceKitServer {
2728
/// Additional options for the index.
2829
public var indexOptions: IndexOptions
2930

30-
public init(buildSetup: BuildSetup = .default, clangdOptions: [String] = [], indexOptions: IndexOptions = .init()) {
31+
/// Options for code-completion.
32+
public var completionOptions: SKCompletionOptions
33+
34+
public init(
35+
buildSetup: BuildSetup = .default,
36+
clangdOptions: [String] = [],
37+
indexOptions: IndexOptions = .init(),
38+
completionOptions: SKCompletionOptions = .init())
39+
{
3140
self.buildSetup = buildSetup
3241
self.clangdOptions = clangdOptions
3342
self.indexOptions = indexOptions
43+
self.completionOptions = completionOptions
3444
}
3545
}
3646
}

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public final class SourceKitServer: LanguageServer {
3636
var language: Language
3737
}
3838

39-
let options: Options
39+
var options: Options
4040

4141
let toolchainRegistry: ToolchainRegistry
4242

@@ -412,6 +412,21 @@ extension SourceKitServer {
412412
if case .bool(let listenToUnitEvents) = options["listenToUnitEvents"] {
413413
indexOptions.listenToUnitEvents = listenToUnitEvents
414414
}
415+
if case .dictionary(let completionOptions) = options["completion"] {
416+
if case .bool(let serverSideFiltering) = completionOptions["serverSideFiltering"] {
417+
self.options.completionOptions.serverSideFiltering = serverSideFiltering
418+
}
419+
switch completionOptions["maxResults"] {
420+
case .none:
421+
break
422+
case .some(.null):
423+
self.options.completionOptions.maxResults = nil
424+
case .some(.int(let maxResults)):
425+
self.options.completionOptions.maxResults = maxResults
426+
case .some(let invalid):
427+
log("expected null or int for 'maxResults'; got \(invalid)", level: .warning)
428+
}
429+
}
415430
}
416431

417432
// Any messages sent before initialize returns are expected to fail, so this will run before
@@ -460,7 +475,7 @@ extension SourceKitServer {
460475
save: .value(TextDocumentSyncOptions.SaveOptions(includeText: false))
461476
),
462477
hoverProvider: true,
463-
completionProvider: CompletionOptions(
478+
completionProvider: LanguageServerProtocol.CompletionOptions(
464479
resolveProvider: false,
465480
triggerCharacters: ["."]
466481
),
@@ -996,7 +1011,11 @@ public func languageService(
9961011

9971012
case .swift:
9981013
guard let sourcekitd = toolchain.sourcekitd else { return nil }
999-
return try makeLocalSwiftServer(client: client, sourcekitd: sourcekitd, clientCapabilities: workspace.clientCapabilities)
1014+
return try makeLocalSwiftServer(
1015+
client: client,
1016+
sourcekitd: sourcekitd,
1017+
clientCapabilities: workspace.clientCapabilities,
1018+
options: options)
10001019

10011020
default:
10021021
return nil

0 commit comments

Comments
 (0)