2
2
import * as Atom from "atom"
3
3
import * as ACP from "atom/autocomplete-plus"
4
4
import * as fuzzaldrin from "fuzzaldrin"
5
+ import { CompletionEntryDetails , CompletionEntryIdentifier } from "typescript/lib/protocol"
5
6
import { GetClientFunction , TSClient } from "../../client"
7
+ import { handlePromise } from "../../utils"
8
+ import { ApplyEdits } from "../pluginManager"
9
+ import { codeActionTemplate } from "./codeActionTemplate"
6
10
import { FileLocationQuery , spanToRange , typeScriptScopes } from "./utils"
11
+ import { selectListView } from "./views/simpleSelectionView"
7
12
8
13
type SuggestionWithDetails = ACP . TextSuggestion & {
9
14
replacementRange ?: Atom . Range
10
15
isMemberCompletion ?: boolean
16
+ identifier ?: CompletionEntryIdentifier | string
17
+ hasAction ?: boolean
11
18
}
12
19
13
20
interface Details {
21
+ details : CompletionEntryDetails
14
22
rightLabel : string
15
23
description ?: string
16
24
}
@@ -41,7 +49,7 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
41
49
details : Map < string , Details >
42
50
}
43
51
44
- constructor ( private getClient : GetClientFunction ) { }
52
+ constructor ( private getClient : GetClientFunction , private applyEdits : ApplyEdits ) { }
45
53
46
54
public async getSuggestions ( opts : ACP . SuggestionsRequestedEvent ) : Promise < ACP . AnySuggestion [ ] > {
47
55
const location = getLocationQuery ( opts )
@@ -91,10 +99,45 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
91
99
}
92
100
}
93
101
102
+ public onDidInsertSuggestion ( evt : ACP . SuggestionInsertedEvent ) {
103
+ const s = evt . suggestion as SuggestionWithDetails
104
+ if ( ! s . hasAction ) return
105
+ if ( ! this . lastSuggestions ) return
106
+ const client = this . lastSuggestions . client
107
+ let details = this . getDetailsFromCache ( s )
108
+ handlePromise (
109
+ ( async ( ) => {
110
+ if ( ! details ) details = await this . getAdditionalDetails ( s )
111
+ if ( ! details ?. details . codeActions ) return
112
+ let action
113
+ if ( details . details . codeActions . length === 1 ) {
114
+ action = details . details . codeActions [ 0 ]
115
+ } else {
116
+ action = await selectListView ( {
117
+ items : details . details . codeActions ,
118
+ itemTemplate : codeActionTemplate ,
119
+ itemFilterKey : "description" ,
120
+ } )
121
+ }
122
+ if ( ! action ) return
123
+ await this . applyEdits ( action . changes )
124
+ if ( ! action . commands ) return
125
+ await Promise . all (
126
+ action . commands . map ( ( cmd ) =>
127
+ client . execute ( "applyCodeActionCommand" , {
128
+ command : cmd ,
129
+ } ) ,
130
+ ) ,
131
+ )
132
+ } ) ( ) ,
133
+ )
134
+ }
135
+
94
136
private async getAdditionalDetails ( suggestion : SuggestionWithDetails ) {
137
+ if ( suggestion . identifier === undefined ) return null
95
138
if ( ! this . lastSuggestions ) return null
96
139
const reply = await this . lastSuggestions . client . execute ( "completionEntryDetails" , {
97
- entryNames : [ suggestion . displayText ! ] ,
140
+ entryNames : [ suggestion . identifier ] ,
98
141
...this . lastSuggestions . location ,
99
142
} )
100
143
if ( ! reply . body ) return null
@@ -111,11 +154,17 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
111
154
) {
112
155
parts = parts . slice ( 3 )
113
156
}
114
- const rightLabel = parts . map ( ( d ) => d . text ) . join ( "" )
157
+ let rightLabel = parts . map ( ( d ) => d . text ) . join ( "" )
158
+ const actionDesc =
159
+ suggestion . hasAction && details . codeActions ?. length === 1
160
+ ? `${ details . codeActions [ 0 ] . description } \n\n`
161
+ : ""
162
+ if ( actionDesc ) rightLabel = actionDesc
115
163
const description =
164
+ actionDesc +
116
165
details . displayParts . map ( ( d ) => d . text ) . join ( "" ) +
117
166
( details . documentation ? "\n\n" + details . documentation . map ( ( d ) => d . text ) . join ( " " ) : "" )
118
- this . lastSuggestions . details . set ( suggestion . displayText ! , { rightLabel, description} )
167
+ this . lastSuggestions . details . set ( suggestion . displayText ! , { details , rightLabel, description} )
119
168
return {
120
169
...suggestion ,
121
170
details,
@@ -264,6 +313,8 @@ function completionEntryToSuggestion(
264
313
replacementRange : entry . replacementSpan ? spanToRange ( entry . replacementSpan ) : undefined ,
265
314
type : kindMap [ entry . kind ] ,
266
315
isMemberCompletion,
316
+ identifier : entry . source !== undefined ? { name : entry . name , source : entry . source } : entry . name ,
317
+ hasAction : entry . hasAction ,
267
318
}
268
319
}
269
320
0 commit comments