@@ -1199,31 +1199,59 @@ namespace ts.Completions {
1199
1199
function createSnippetPrinter (
1200
1200
printerOptions : PrinterOptions ,
1201
1201
) {
1202
+ let escapes : TextChange [ ] | undefined ;
1202
1203
const baseWriter = textChanges . createWriter ( getNewLineCharacter ( printerOptions ) ) ;
1203
1204
const printer = createPrinter ( printerOptions , baseWriter ) ;
1204
1205
const writer : EmitTextWriter = {
1205
1206
...baseWriter ,
1206
- write : s => baseWriter . write ( escapeSnippetText ( s ) ) ,
1207
+ write : s => escapingWrite ( s , ( ) => baseWriter . write ( s ) ) ,
1207
1208
nonEscapingWrite : baseWriter . write ,
1208
- writeLiteral : s => baseWriter . writeLiteral ( escapeSnippetText ( s ) ) ,
1209
- writeStringLiteral : s => baseWriter . writeStringLiteral ( escapeSnippetText ( s ) ) ,
1210
- writeSymbol : ( s , symbol ) => baseWriter . writeSymbol ( escapeSnippetText ( s ) , symbol ) ,
1211
- writeParameter : s => baseWriter . writeParameter ( escapeSnippetText ( s ) ) ,
1212
- writeComment : s => baseWriter . writeComment ( escapeSnippetText ( s ) ) ,
1213
- writeProperty : s => baseWriter . writeProperty ( escapeSnippetText ( s ) ) ,
1209
+ writeLiteral : s => escapingWrite ( s , ( ) => baseWriter . writeLiteral ( s ) ) ,
1210
+ writeStringLiteral : s => escapingWrite ( s , ( ) => baseWriter . writeStringLiteral ( s ) ) ,
1211
+ writeSymbol : ( s , symbol ) => escapingWrite ( s , ( ) => baseWriter . writeSymbol ( s , symbol ) ) ,
1212
+ writeParameter : s => escapingWrite ( s , ( ) => baseWriter . writeParameter ( s ) ) ,
1213
+ writeComment : s => escapingWrite ( s , ( ) => baseWriter . writeComment ( s ) ) ,
1214
+ writeProperty : s => escapingWrite ( s , ( ) => baseWriter . writeProperty ( s ) ) ,
1214
1215
} ;
1215
1216
1216
1217
return {
1217
1218
printSnippetList,
1218
1219
printAndFormatSnippetList,
1219
1220
} ;
1220
1221
1222
+ // The formatter/scanner will have issues with snippet-escaped text,
1223
+ // so instead of writing the escaped text directly to the writer,
1224
+ // generate a set of changes that can be applied to the unescaped text
1225
+ // to escape it post-formatting.
1226
+ function escapingWrite ( s : string , write : ( ) => void ) {
1227
+ const escaped = escapeSnippetText ( s ) ;
1228
+ if ( escaped !== s ) {
1229
+ const start = baseWriter . getTextPos ( ) ;
1230
+ write ( ) ;
1231
+ const end = baseWriter . getTextPos ( ) ;
1232
+ escapes = append ( escapes ||= [ ] , { newText : escaped , span : { start, length : end - start } } ) ;
1233
+ }
1234
+ else {
1235
+ write ( ) ;
1236
+ }
1237
+ }
1238
+
1221
1239
/* Snippet-escaping version of `printer.printList`. */
1222
1240
function printSnippetList (
1223
1241
format : ListFormat ,
1224
1242
list : NodeArray < Node > ,
1225
1243
sourceFile : SourceFile | undefined ,
1226
1244
) : string {
1245
+ const unescaped = printUnescapedSnippetList ( format , list , sourceFile ) ;
1246
+ return escapes ? textChanges . applyChanges ( unescaped , escapes ) : unescaped ;
1247
+ }
1248
+
1249
+ function printUnescapedSnippetList (
1250
+ format : ListFormat ,
1251
+ list : NodeArray < Node > ,
1252
+ sourceFile : SourceFile | undefined ,
1253
+ ) : string {
1254
+ escapes = undefined ;
1227
1255
writer . clear ( ) ;
1228
1256
printer . writeList ( format , list , sourceFile , writer ) ;
1229
1257
return writer . getText ( ) ;
@@ -1236,7 +1264,7 @@ namespace ts.Completions {
1236
1264
formatContext : formatting . FormatContext ,
1237
1265
) : string {
1238
1266
const syntheticFile = {
1239
- text : printSnippetList (
1267
+ text : printUnescapedSnippetList (
1240
1268
format ,
1241
1269
list ,
1242
1270
sourceFile ) ,
@@ -1256,7 +1284,11 @@ namespace ts.Completions {
1256
1284
/* delta */ 0 ,
1257
1285
{ ...formatContext , options : formatOptions } ) ;
1258
1286
} ) ;
1259
- return textChanges . applyChanges ( syntheticFile . text , changes ) ;
1287
+
1288
+ const allChanges = escapes
1289
+ ? stableSort ( concatenate ( changes , escapes ) , ( a , b ) => compareTextSpans ( a . span , b . span ) )
1290
+ : changes ;
1291
+ return textChanges . applyChanges ( syntheticFile . text , allChanges ) ;
1260
1292
}
1261
1293
}
1262
1294
0 commit comments