@@ -11,27 +11,60 @@ import { RazorLanguageServiceClient } from '../RazorLanguageServiceClient';
11
11
import { RazorLogger } from '../RazorLogger' ;
12
12
import { getUriPath } from '../UriPaths' ;
13
13
import { ProvisionalCompletionOrchestrator } from './ProvisionalCompletionOrchestrator' ;
14
+ import { LanguageKind } from '../RPC/LanguageKind' ;
15
+ import { RoslynLanguageServer } from '../../../lsptoolshost/roslynLanguageServer' ;
16
+ import { CompletionItem , CompletionParams , CompletionTriggerKind } from 'vscode-languageclient' ;
17
+ import { UriConverter } from '../../../lsptoolshost/uriConverter' ;
18
+ import * as RazorConventions from '../RazorConventions' ;
19
+ import { MappingHelpers } from '../Mapping/MappingHelpers' ;
14
20
15
21
export class RazorCompletionItemProvider
16
22
extends RazorLanguageFeatureBase
17
23
implements vscode . CompletionItemProvider {
18
24
19
25
public static async getCompletions (
20
26
projectedUri : vscode . Uri , hostDocumentPosition : vscode . Position ,
21
- projectedPosition : vscode . Position , triggerCharacter : string | undefined ) {
27
+ projectedPosition : vscode . Position , context : vscode . CompletionContext ,
28
+ language : LanguageKind ) {
22
29
23
30
if ( projectedUri ) {
24
31
// "@" is not a valid trigger character for C# / HTML and therefore we need to translate
25
32
// it into a non-trigger invocation.
26
- const modifiedTriggerCharacter = triggerCharacter === '@' ? undefined : triggerCharacter ;
27
-
28
- const completions = await vscode
29
- . commands
30
- . executeCommand < vscode . CompletionList | vscode . CompletionItem [ ] > (
31
- 'vscode.executeCompletionItemProvider' ,
32
- projectedUri ,
33
- projectedPosition ,
34
- modifiedTriggerCharacter ) ;
33
+ const modifiedTriggerCharacter = context . triggerCharacter === '@' ? undefined : context . triggerCharacter ;
34
+
35
+ let completions : vscode . CompletionList | vscode . CompletionItem [ ] ;
36
+
37
+ // For CSharp, completions need to keep the "data" field
38
+ // on the completion item for lazily resolving the edits in
39
+ // the resolveCompletionItem step. Using the vs code command
40
+ // drops that field because it doesn't exist in the declared vs code
41
+ // CompletionItem type.
42
+ if ( language === LanguageKind . CSharp ) {
43
+ const params : CompletionParams = {
44
+ context : {
45
+ triggerKind : getTriggerKind ( context . triggerKind ) ,
46
+ triggerCharacter : modifiedTriggerCharacter
47
+ } ,
48
+ textDocument : {
49
+ uri : UriConverter . serialize ( projectedUri ) ,
50
+ } ,
51
+ position : projectedPosition
52
+ } ;
53
+
54
+ completions = await vscode
55
+ . commands
56
+ . executeCommand < vscode . CompletionList | vscode . CompletionItem [ ] > (
57
+ RoslynLanguageServer . provideCompletionsCommand ,
58
+ params ) ;
59
+ } else {
60
+ completions = await vscode
61
+ . commands
62
+ . executeCommand < vscode . CompletionList | vscode . CompletionItem [ ] > (
63
+ 'vscode.executeCompletionItemProvider' ,
64
+ projectedUri ,
65
+ projectedPosition ,
66
+ modifiedTriggerCharacter ) ;
67
+ }
35
68
36
69
const completionItems =
37
70
completions instanceof Array ? completions // was vscode.CompletionItem[]
@@ -68,7 +101,7 @@ export class RazorCompletionItemProvider
68
101
( range as any ) . replacing = new vscode . Range ( replacingRangeStart , replacingRangeEnd ) ;
69
102
}
70
103
71
- if ( range instanceof vscode . Range && range . start && range . end ) {
104
+ if ( range instanceof vscode . Range && range . start && range . end ) {
72
105
const rangeStart = this . offsetColumn ( completionCharacterOffset , hostDocumentPosition . line , range . start ) ;
73
106
const rangeEnd = this . offsetColumn ( completionCharacterOffset , hostDocumentPosition . line , range . end ) ;
74
107
completionItem . range = new vscode . Range ( rangeStart , rangeEnd ) ;
@@ -78,7 +111,7 @@ export class RazorCompletionItemProvider
78
111
// textEdit is deprecated in favor of .range. Clear out its value to avoid any unexpected behavior.
79
112
completionItem . textEdit = undefined ;
80
113
81
- if ( triggerCharacter === '@' &&
114
+ if ( context . triggerCharacter === '@' &&
82
115
completionItem . commitCharacters ) {
83
116
// We remove `{`, '(', and '*' from the commit characters to prevent auto-completing the first
84
117
// completion item with a curly brace when a user intended to type `@{}` or `@()`.
@@ -138,7 +171,61 @@ export class RazorCompletionItemProvider
138
171
projection . uri ,
139
172
position ,
140
173
projection . position ,
141
- context . triggerCharacter ) ;
174
+ context ,
175
+ projection . languageKind ) ;
176
+
142
177
return completionList ;
143
178
}
179
+
180
+ public async resolveCompletionItem ( item : vscode . CompletionItem , token : vscode . CancellationToken ) : Promise < vscode . CompletionItem > {
181
+ // We assume that only the RoslynLanguageServer provides data, which
182
+ // if it does we use LSP calls directly to Roslyn since there's no
183
+ // equivalent vscode command to generically do that.
184
+ if ( ( < CompletionItem > item ) . data ) {
185
+ let newItem = await vscode
186
+ . commands
187
+ . executeCommand < vscode . CompletionItem > (
188
+ RoslynLanguageServer . resolveCompletionsCommand ,
189
+ item ) ;
190
+
191
+ if ( ! newItem ) {
192
+ return item ;
193
+ }
194
+
195
+ item = newItem ;
196
+
197
+ if ( item . command && item . command . arguments ?. length === 4 ) {
198
+ let uri = vscode . Uri . parse ( item . command . arguments [ 0 ] ) ;
199
+
200
+ if ( uri && RazorConventions . isRazorCSharpFile ( uri ) ) {
201
+ let razorUri = RazorConventions . getRazorDocumentUri ( uri ) ;
202
+ let textEdit = item . command . arguments [ 1 ] as vscode . TextEdit ;
203
+
204
+ let remappedEdit = await MappingHelpers . remapGeneratedFileTextEdit ( razorUri , textEdit , this . serviceClient , this . logger , token ) ;
205
+
206
+ if ( remappedEdit ) {
207
+ item . command . arguments [ 0 ] = razorUri ;
208
+ item . command . arguments [ 1 ] = remappedEdit ;
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ return item ;
215
+ }
216
+ }
217
+
218
+ function getTriggerKind ( triggerKind : vscode . CompletionTriggerKind ) : CompletionTriggerKind {
219
+ switch ( triggerKind ) {
220
+ case vscode . CompletionTriggerKind . Invoke :
221
+ return CompletionTriggerKind . Invoked ;
222
+ case vscode . CompletionTriggerKind . TriggerCharacter :
223
+ return CompletionTriggerKind . TriggerCharacter ;
224
+ case vscode . CompletionTriggerKind . TriggerForIncompleteCompletions :
225
+ return CompletionTriggerKind . TriggerForIncompleteCompletions ;
226
+ default :
227
+ throw new Error ( `Unexpected completion trigger kind: ${ triggerKind } ` ) ;
228
+
229
+ }
144
230
}
231
+
0 commit comments