@@ -172,15 +172,15 @@ module ts.SignatureHelp {
172
172
return undefined ;
173
173
}
174
174
175
- var argumentList = getContainingArgumentList ( startingToken ) ;
175
+ var argumentInfo = getContainingArgumentInfo ( startingToken ) ;
176
176
cancellationToken . throwIfCancellationRequested ( ) ;
177
177
178
178
// Semantic filtering of signature help
179
- if ( ! argumentList ) {
179
+ if ( ! argumentInfo ) {
180
180
return undefined ;
181
181
}
182
182
183
- var call = < CallExpression > argumentList . parent ;
183
+ var call = < CallExpression > argumentInfo . list . parent ;
184
184
var candidates = < Signature [ ] > [ ] ;
185
185
var resolvedSignature = typeInfoResolver . getResolvedSignature ( call , candidates ) ;
186
186
cancellationToken . throwIfCancellationRequested ( ) ;
@@ -189,13 +189,13 @@ module ts.SignatureHelp {
189
189
return undefined ;
190
190
}
191
191
192
- return createSignatureHelpItems ( candidates , resolvedSignature , argumentList ) ;
192
+ return createSignatureHelpItems ( candidates , resolvedSignature , argumentInfo ) ;
193
193
194
194
/**
195
195
* If node is an argument, returns its index in the argument list.
196
196
* If not, returns -1.
197
197
*/
198
- function getImmediatelyContainingArgumentList ( node : Node ) : Node {
198
+ function getImmediatelyContainingArgumentInfo ( node : Node ) : ListItemInfo {
199
199
if ( node . parent . kind !== SyntaxKind . CallExpression && node . parent . kind !== SyntaxKind . NewExpression ) {
200
200
return undefined ;
201
201
}
@@ -216,10 +216,14 @@ module ts.SignatureHelp {
216
216
var parent = < CallExpression > node . parent ;
217
217
// Find out if 'node' is an argument, a type argument, or neither
218
218
if ( node . kind === SyntaxKind . LessThanToken || node . kind === SyntaxKind . OpenParenToken ) {
219
- // Find the list that starts right *after* the < or ( token
219
+ // Find the list that starts right *after* the < or ( token.
220
+ // If the user has just opened a list, consider this item 0.
220
221
var list = getChildListThatStartsWithOpenerToken ( parent , node , sourceFile ) ;
221
222
Debug . assert ( list ) ;
222
- return list ;
223
+ return {
224
+ list : list ,
225
+ listItemIndex : 0
226
+ } ;
223
227
}
224
228
225
229
if ( node . kind === SyntaxKind . GreaterThanToken
@@ -228,18 +232,18 @@ module ts.SignatureHelp {
228
232
return undefined ;
229
233
}
230
234
231
- return findContainingList ( node ) ;
235
+ return findListItemInfo ( node ) ;
232
236
}
233
237
234
- function getContainingArgumentList ( node : Node ) : Node {
238
+ function getContainingArgumentInfo ( node : Node ) : ListItemInfo {
235
239
for ( var n = node ; n . kind !== SyntaxKind . SourceFile ; n = n . parent ) {
236
240
if ( n . kind === SyntaxKind . FunctionBlock ) {
237
241
return undefined ;
238
242
}
239
243
240
- var argumentList = getImmediatelyContainingArgumentList ( n ) ;
241
- if ( argumentList ) {
242
- return argumentList ;
244
+ var argumentInfo = getImmediatelyContainingArgumentInfo ( n ) ;
245
+ if ( argumentInfo ) {
246
+ return argumentInfo ;
243
247
}
244
248
245
249
@@ -248,7 +252,8 @@ module ts.SignatureHelp {
248
252
return undefined ;
249
253
}
250
254
251
- function createSignatureHelpItems ( candidates : Signature [ ] , bestSignature : Signature , argumentListOrTypeArgumentList : Node ) : SignatureHelpItems {
255
+ function createSignatureHelpItems ( candidates : Signature [ ] , bestSignature : Signature , argumentInfoOrTypeArgumentInfo : ListItemInfo ) : SignatureHelpItems {
256
+ var argumentListOrTypeArgumentList = argumentInfoOrTypeArgumentInfo . list ;
252
257
var items : SignatureHelpItem [ ] = map ( candidates , candidateSignature => {
253
258
var parameters = candidateSignature . parameters ;
254
259
var parameterHelpItems : SignatureHelpParameter [ ] = parameters . length === 0 ? emptyArray : map ( parameters , p => {
@@ -338,63 +343,28 @@ module ts.SignatureHelp {
338
343
var applicableSpanEnd = skipTrivia ( sourceFile . text , argumentListOrTypeArgumentList . end , /*stopAfterLineBreak*/ false ) ;
339
344
var applicableSpan = new TypeScript . TextSpan ( applicableSpanStart , applicableSpanEnd - applicableSpanStart ) ;
340
345
341
- var state = getSignatureHelpCurrentArgumentState ( sourceFile , position , applicableSpanStart ) ;
346
+ // The listItemIndex we got back includes commas. Our goal is to return the index of the proper
347
+ // item (not including commas). Here are some examples:
348
+ // 1. foo(a, b, c $) -> the listItemIndex is 4, we want to return 2
349
+ // 2. foo(a, b, $ c) -> listItemIndex is 3, we want to return 2
350
+ // 3. foo($a) -> listItemIndex is 0, we want to return 0
351
+ //
352
+ // In general, we want to subtract the number of commas before the current index.
353
+ // But if we are on a comma, we also want to pretend we are on the argument *following*
354
+ // the comma. That amounts to taking the ceiling of half the index.
355
+ var argumentIndex = ( argumentInfoOrTypeArgumentInfo . listItemIndex + 1 ) >> 1 ;
356
+ var numberOfCommas = countWhere ( argumentListOrTypeArgumentList . getChildren ( ) , arg => arg . kind === SyntaxKind . CommaToken ) ;
357
+ var argumentCount = numberOfCommas + 1 ;
342
358
return {
343
359
items : items ,
344
360
applicableSpan : applicableSpan ,
345
361
selectedItemIndex : selectedItemIndex ,
346
- argumentIndex : state . argumentIndex ,
347
- argumentCount : state . argumentCount
362
+ argumentIndex : argumentIndex ,
363
+ argumentCount : argumentCount
348
364
} ;
349
365
}
350
366
}
351
367
352
- function getSignatureHelpCurrentArgumentState ( sourceFile : SourceFile , position : number , applicableSpanStart : number ) : { argumentIndex : number ; argumentCount : number } {
353
- var tokenPrecedingSpanStart = findPrecedingToken ( applicableSpanStart , sourceFile ) ;
354
- if ( ! tokenPrecedingSpanStart ) {
355
- return undefined ;
356
- }
357
-
358
- if ( tokenPrecedingSpanStart . kind !== SyntaxKind . OpenParenToken && tokenPrecedingSpanStart . kind !== SyntaxKind . LessThanToken ) {
359
- // The span start must have moved backward in the file (for example if the open paren was backspaced)
360
- return undefined ;
361
- }
362
-
363
- var tokenPrecedingCurrentPosition = findPrecedingToken ( position , sourceFile ) ;
364
- var call = < CallExpression > tokenPrecedingSpanStart . parent ;
365
- Debug . assert ( call . kind === SyntaxKind . CallExpression || call . kind === SyntaxKind . NewExpression , "wrong call kind " + SyntaxKind [ call . kind ] ) ;
366
- if ( tokenPrecedingCurrentPosition . kind === SyntaxKind . CloseParenToken || tokenPrecedingCurrentPosition . kind === SyntaxKind . GreaterThanToken ) {
367
- if ( tokenPrecedingCurrentPosition . parent === call ) {
368
- // This call expression is complete. Stop signature help.
369
- return undefined ;
370
- }
371
- }
372
-
373
- var argumentListOrTypeArgumentList = getChildListThatStartsWithOpenerToken ( call , tokenPrecedingSpanStart , sourceFile ) ;
374
- // Debug.assert(argumentListOrTypeArgumentList.getChildCount() === 0 || argumentListOrTypeArgumentList.getChildCount() % 2 === 1, "Even number of children");
375
-
376
- // The call might be finished, but incorrectly. Check if we are still within the bounds of the call
377
- if ( position > skipTrivia ( sourceFile . text , argumentListOrTypeArgumentList . end , /*stopAfterLineBreak*/ false ) ) {
378
- return undefined ;
379
- }
380
-
381
- var numberOfCommas = countWhere ( argumentListOrTypeArgumentList . getChildren ( ) , arg => arg . kind === SyntaxKind . CommaToken ) ;
382
- var argumentCount = numberOfCommas + 1 ;
383
- if ( argumentCount <= 1 ) {
384
- return { argumentIndex : 0 , argumentCount : argumentCount } ;
385
- }
386
-
387
- var indexOfNodeContainingPosition = findListItemIndexContainingPosition ( argumentListOrTypeArgumentList , position ) ;
388
-
389
- // indexOfNodeContainingPosition checks that position is between pos and end of each child, so it is
390
- // possible that we are to the right of all children. Assume that we are still within
391
- // the applicable span and that we are typing the last argument
392
- // Alternatively, we could be in range of one of the arguments, in which case we need to divide
393
- // by 2 to exclude commas. Use bit shifting in order to take the floor of the division.
394
- var argumentIndex = indexOfNodeContainingPosition < 0 ? argumentCount - 1 : indexOfNodeContainingPosition >> 1 ;
395
- return { argumentIndex : argumentIndex , argumentCount : argumentCount } ;
396
- }
397
-
398
368
function getChildListThatStartsWithOpenerToken ( parent : Node , openerToken : Node , sourceFile : SourceFile ) : Node {
399
369
var children = parent . getChildren ( sourceFile ) ;
400
370
var indexOfOpenerToken = children . indexOf ( openerToken ) ;
0 commit comments