@@ -203,12 +203,19 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
203
203
}
204
204
205
205
const actions = detail ?. codeActions ;
206
+ const isImport = ! ! detail ?. source ;
207
+
206
208
if ( actions ) {
207
209
const edit : TextEdit [ ] = [ ] ;
208
210
209
211
for ( const action of actions ) {
210
212
for ( const change of action . changes ) {
211
- edit . push ( ...this . codeActionChangesToTextEdit ( document , fragment , change ) ) ;
213
+ edit . push ( ...this . codeActionChangesToTextEdit (
214
+ document ,
215
+ fragment ,
216
+ change ,
217
+ isImport
218
+ ) ) ;
212
219
}
213
220
}
214
221
@@ -241,16 +248,18 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
241
248
doc : Document ,
242
249
fragment : SvelteSnapshotFragment ,
243
250
changes : ts . FileTextChanges ,
251
+ isImport : boolean ,
244
252
) : TextEdit [ ] {
245
253
return changes . textChanges . map ( ( change ) =>
246
- this . codeActionChangeToTextEdit ( doc , fragment , change ) ,
254
+ this . codeActionChangeToTextEdit ( doc , fragment , change , isImport ) ,
247
255
) ;
248
256
}
249
257
250
258
private codeActionChangeToTextEdit (
251
259
doc : Document ,
252
260
fragment : SvelteSnapshotFragment ,
253
261
change : ts . TextChange ,
262
+ isImport : boolean ,
254
263
) : TextEdit {
255
264
change . newText = this . changeSvelteComponentName ( change . newText ) ;
256
265
@@ -264,28 +273,58 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
264
273
}
265
274
266
275
const { span } = change ;
267
- // prevent newText from being placed like this: <script>import {} from ''
268
- if ( span . start === 0 ) {
269
- change . newText = ts . sys . newLine + change . newText ;
276
+
277
+ const virutalRange = convertRange ( fragment , span ) ;
278
+ let range : Range ;
279
+ const isNewImport = isImport && virutalRange . start . character === 0 ;
280
+
281
+ // Since new import always can't be mapped, we'll have special treatment here
282
+ // but only hack this when there is multiple line in script
283
+ if ( isNewImport && virutalRange . start . line > 1 ) {
284
+ range = this . mapRangeForNewImport ( fragment , virutalRange ) ;
285
+ } else {
286
+ range = mapRangeToOriginal ( fragment , virutalRange ) ;
270
287
}
271
288
272
- let range = mapRangeToOriginal ( fragment , convertRange ( fragment , span ) ) ;
273
- // If range is somehow not mapped in parent or the import is mapped wrong ,
289
+ // If range is somehow not mapped in parent,
290
+ // the import is mapped wrong or is outside script tag ,
274
291
// use script starting point instead.
275
292
// This happens among other things if the completion is the first import of the file.
276
293
if (
277
294
range . start . line === - 1 ||
278
- ( range . start . line === 0 && range . start . character <= 1 && span . length === 0 )
295
+ ( range . start . line === 0 && range . start . character <= 1 && span . length === 0 ) ||
296
+ doc . offsetAt ( range . start ) > scriptTagInfo . end
279
297
) {
280
298
range = convertRange ( doc , {
281
299
start : scriptTagInfo . start ,
282
300
length : span . length ,
283
301
} ) ;
284
302
}
303
+ // prevent newText from being placed like this: <script>import {} from ''
304
+ if ( range . start . line === 0 ) {
305
+ change . newText = ts . sys . newLine + change . newText ;
306
+ }
285
307
286
308
return TextEdit . replace ( range , change . newText ) ;
287
309
}
288
310
311
+ private mapRangeForNewImport (
312
+ fragment : SvelteSnapshotFragment ,
313
+ virtualRange : Range
314
+ ) {
315
+ const sourceMapableRange = this . offsetLinesAndMovetoStartOfLine ( virtualRange , - 1 ) ;
316
+ const mappableRange = mapRangeToOriginal (
317
+ fragment , sourceMapableRange ) ;
318
+ return this . offsetLinesAndMovetoStartOfLine ( mappableRange , 1 ) ;
319
+ }
320
+
321
+ private offsetLinesAndMovetoStartOfLine ( { start, end } : Range , offsetLines : number ) {
322
+ return Range . create (
323
+ Position . create ( start . line + offsetLines , 0 ) ,
324
+ Position . create ( end . line + offsetLines , 0 )
325
+ ) ;
326
+ }
327
+
289
328
private isSvelteComponentImport ( className : string ) {
290
329
return className . endsWith ( '__SvelteComponent_' ) ;
291
330
}
0 commit comments