@@ -3479,8 +3479,36 @@ module ts {
3479
3479
return emitOutput ;
3480
3480
}
3481
3481
3482
+ function getChildListThatStartsWithOpenerToken ( parent : Node , openerToken : Node , sourceFile : SourceFile ) : Node {
3483
+ var children = parent . getChildren ( sourceFile ) ;
3484
+ var indexOfOpenerToken = children . indexOf ( openerToken ) ;
3485
+ return children [ indexOfOpenerToken + 1 ] ;
3486
+ }
3487
+
3482
3488
// Signature help
3483
3489
function getSignatureHelpItems ( fileName : string , position : number ) : SignatureHelpItems {
3490
+ synchronizeHostData ( ) ;
3491
+
3492
+ // Decide whether to show signature help
3493
+ fileName = TypeScript . switchToForwardSlashes ( fileName ) ;
3494
+ var sourceFile = getSourceFile ( fileName ) ;
3495
+ var node = getNodeAtPosition ( sourceFile , position ) ;
3496
+
3497
+
3498
+ // Semantic filtering of signature help
3499
+ var signatureHelpContext = getSignatureHelpArgumentContext ( node ) ;
3500
+ if ( signatureHelpContext ) {
3501
+ var call = < CallExpression > signatureHelpContext . list . parent ;
3502
+ var candidates = < Signature [ ] > [ ] ;
3503
+ var resolvedSignature = typeInfoResolver . getResolvedSignature ( call , candidates ) ;
3504
+ return candidates . length
3505
+ ? createSignatureHelpItems ( candidates , resolvedSignature , signatureHelpContext . list )
3506
+ : undefined ;
3507
+ }
3508
+
3509
+ return undefined ;
3510
+
3511
+
3484
3512
// If node is an argument, returns its index in the argument list
3485
3513
// If not, returns -1
3486
3514
function getArgumentIndexInfo ( node : Node ) : ServicesSyntaxUtilities . ListItemInfo {
@@ -3492,16 +3520,7 @@ module ts {
3492
3520
// Find out if 'node' is an argument, a type argument, or neither
3493
3521
if ( node . kind === SyntaxKind . LessThanToken || node . kind === SyntaxKind . OpenParenToken ) {
3494
3522
// Find the list that starts right *after* the < or ( token
3495
- var seenRelevantOpenerToken = false ;
3496
- var list = forEach ( parent . getChildren ( ) , c => {
3497
- if ( seenRelevantOpenerToken ) {
3498
- Debug . assert ( c . kind === SyntaxKind . SyntaxList ) ;
3499
- return c ;
3500
- }
3501
- if ( c . kind === node . kind /*node is the relevant opener token we are looking for*/ ) {
3502
- seenRelevantOpenerToken = true ;
3503
- }
3504
- } ) ;
3523
+ var list = getChildListThatStartsWithOpenerToken ( parent , node , sourceFile ) ;
3505
3524
Debug . assert ( list ) ;
3506
3525
// Treat the open paren / angle bracket of a call as the introduction of parameter slot 0
3507
3526
return {
@@ -3549,7 +3568,7 @@ module ts {
3549
3568
return undefined ;
3550
3569
}
3551
3570
3552
- function getSignatureHelpItemsFromCandidateInfo ( candidates : Signature [ ] , bestSignature : Signature , argumentListOrTypeArgumentList : Node ) : SignatureHelpItems {
3571
+ function createSignatureHelpItems ( candidates : Signature [ ] , bestSignature : Signature , argumentListOrTypeArgumentList : Node ) : SignatureHelpItems {
3553
3572
var items = map ( candidates , candidateSignature => {
3554
3573
var parameters = candidateSignature . parameters ;
3555
3574
var parameterHelpItems = parameters . length === 0 ? emptyArray : map ( parameters , p => {
@@ -3586,32 +3605,49 @@ module ts {
3586
3605
var applicableSpan = new TypeScript . TextSpan ( applicableSpanStart , applicableSpanEnd - applicableSpanStart ) ;
3587
3606
return new SignatureHelpItems ( items , applicableSpan , selectedItemIndex ) ;
3588
3607
}
3608
+ }
3589
3609
3590
- synchronizeHostData ( ) ;
3591
-
3592
- // Decide whether to show signature help
3610
+ function getSignatureHelpCurrentArgumentState ( fileName : string , position : number , applicableSpanStart : number ) : SignatureHelpState {
3593
3611
fileName = TypeScript . switchToForwardSlashes ( fileName ) ;
3594
- var sourceFile = getSourceFile ( fileName ) ;
3595
- var node = getNodeAtPosition ( sourceFile , position ) ;
3612
+ var sourceFile = getCurrentSourceFile ( fileName ) ;
3613
+ var tokenPrecedingSpanStart = ServicesSyntaxUtilities . findPrecedingToken ( applicableSpanStart , sourceFile ) ;
3614
+ if ( tokenPrecedingSpanStart . kind !== SyntaxKind . OpenParenToken && tokenPrecedingSpanStart . kind !== SyntaxKind . LessThanToken ) {
3615
+ // The span start must have moved backward in the file (for example if the open paren was backspaced)
3616
+ return undefined ;
3617
+ }
3596
3618
3619
+ var tokenPrecedingCurrentPosition = ServicesSyntaxUtilities . findPrecedingToken ( position , sourceFile ) ;
3620
+ var call = < CallExpression > tokenPrecedingSpanStart . parent ;
3621
+ if ( tokenPrecedingCurrentPosition . kind === SyntaxKind . CloseParenToken || tokenPrecedingCurrentPosition . kind === SyntaxKind . GreaterThanToken ) {
3622
+ if ( tokenPrecedingCurrentPosition . parent === call ) {
3623
+ // This call expression is complete. Stop signature help.
3624
+ return undefined ;
3625
+ }
3626
+ // TODO(jfreeman): handle other (incorrect) ways that a call expression can end
3627
+ }
3597
3628
3598
- // Semantic filtering of signature help
3599
- var signatureHelpContext = getSignatureHelpArgumentContext ( node ) ;
3600
- if ( signatureHelpContext ) {
3601
- var call = < CallExpression > signatureHelpContext . list . parent ;
3602
- var candidates = < Signature [ ] > [ ] ;
3603
- var resolvedSignature = typeInfoResolver . getResolvedSignature ( call , candidates ) ;
3604
- return candidates . length
3605
- ? getSignatureHelpItemsFromCandidateInfo ( candidates , resolvedSignature , signatureHelpContext . list )
3606
- : undefined ;
3629
+ Debug . assert ( call . kind === SyntaxKind . CallExpression || call . kind === SyntaxKind . NewExpression , "wrong call kind " + SyntaxKind [ call . kind ] ) ;
3630
+
3631
+ var argumentListOrTypeArgumentList = getChildListThatStartsWithOpenerToken ( call , tokenPrecedingSpanStart , sourceFile ) ;
3632
+ // Debug.assert(argumentListOrTypeArgumentList.getChildCount() === 0 || argumentListOrTypeArgumentList.getChildCount() % 2 === 1, "Even number of children");
3633
+
3634
+ var numberOfCommas = countWhere ( argumentListOrTypeArgumentList . getChildren ( ) , arg => arg . kind === SyntaxKind . CommaToken ) ;
3635
+ var argumentCount = numberOfCommas + 1 ;
3636
+
3637
+
3638
+ if ( argumentCount <= 1 ) {
3639
+ return new SignatureHelpState ( /*argumentIndex*/ 0 , argumentCount ) ;
3607
3640
}
3608
3641
3609
- return undefined ;
3610
- }
3642
+ var indexOfNodeContainingPosition = ServicesSyntaxUtilities . findListItemIndexContainingPosition ( argumentListOrTypeArgumentList , position ) ;
3611
3643
3612
- function getSignatureHelpCurrentArgumentState ( fileName : string , position : number , applicableSpanStart : number ) : SignatureHelpState {
3613
- synchronizeHostData ( ) ;
3614
- return null ;
3644
+ // indexOfNodeContainingPosition checks that position is between pos and end of each child, so it is
3645
+ // possible that we are to the right of all children. Assume that we are still within
3646
+ // the applicable span and that we are typing the last argument
3647
+ // Alternatively, we could be in range of one of the arguments, in which case we need to divide
3648
+ // by 2 to exclude commas
3649
+ var argumentIndex = indexOfNodeContainingPosition < 0 ? argumentCount - 1 : indexOfNodeContainingPosition / 2 ;
3650
+ return new SignatureHelpState ( argumentIndex , argumentCount ) ;
3615
3651
}
3616
3652
3617
3653
/// Syntactic features
0 commit comments