Skip to content

Commit aa399cd

Browse files
committed
Add support for the params parameter list expansion
1 parent f0a7b37 commit aa399cd

File tree

1 file changed

+54
-8
lines changed

1 file changed

+54
-8
lines changed

Source/ExcelDna.IntelliSense/IntelliSenseDisplay.cs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -487,17 +487,21 @@ IEnumerable<TextLine> GetFunctionDescriptionOrNull(FunctionInfo functionInfo)
487487

488488
FormattedText GetFunctionIntelliSense(FunctionInfo functionInfo, int currentArgIndex)
489489
{
490+
// In case of the special params pattern (x, y, arg1, ...) we base the argument display on an expanded argument list, matching Excel's behaviour,
491+
// and the magic expansion in the function wizard.
492+
var argumentList = GetExpandedArgumentList(functionInfo, currentArgIndex);
493+
490494
var nameLine = new TextLine { new TextRun { Text = functionInfo.Name, LinkAddress = FixHelpTopic(functionInfo.HelpTopic) } };
491495
nameLine.Add(new TextRun { Text = "(" });
492-
if (functionInfo.ArgumentList.Count > 0)
496+
if (argumentList.Count > 0)
493497
{
494-
var argNames = functionInfo.ArgumentList.Take(currentArgIndex).Select(arg => arg.Name).ToArray();
498+
var argNames = argumentList.Take(currentArgIndex).Select(arg => arg.Name).ToArray();
495499
if (argNames.Length >= 1)
496500
{
497501
nameLine.Add(new TextRun { Text = string.Join(_argumentSeparator, argNames) });
498502
}
499503

500-
if (functionInfo.ArgumentList.Count > currentArgIndex)
504+
if (argumentList.Count > currentArgIndex)
501505
{
502506
if (argNames.Length >= 1)
503507
{
@@ -509,11 +513,11 @@ FormattedText GetFunctionIntelliSense(FunctionInfo functionInfo, int currentArgI
509513

510514
nameLine.Add(new TextRun
511515
{
512-
Text = functionInfo.ArgumentList[currentArgIndex].Name,
516+
Text = argumentList[currentArgIndex].Name,
513517
Style = System.Drawing.FontStyle.Bold
514518
});
515519

516-
argNames = functionInfo.ArgumentList.Skip(currentArgIndex + 1).Select(arg => arg.Name).ToArray();
520+
argNames = argumentList.Skip(currentArgIndex + 1).Select(arg => arg.Name).ToArray();
517521
if (argNames.Length >= 1)
518522
{
519523
nameLine.Add(new TextRun {Text = _argumentSeparator + string.Join(_argumentSeparator, argNames)});
@@ -523,18 +527,60 @@ FormattedText GetFunctionIntelliSense(FunctionInfo functionInfo, int currentArgI
523527
nameLine.Add(new TextRun { Text = ")" });
524528

525529
var descriptionLines = GetFunctionDescriptionOrNull(functionInfo);
526-
530+
527531
var formattedText = new FormattedText { nameLine, descriptionLines };
528-
if (functionInfo.ArgumentList.Count > currentArgIndex)
532+
if (argumentList.Count > currentArgIndex)
529533
{
530-
var description = GetArgumentDescriptionOrNull(functionInfo.ArgumentList[currentArgIndex]);
534+
var description = GetArgumentDescriptionOrNull(argumentList[currentArgIndex]);
531535
if (description != null)
532536
formattedText.Add(description);
533537
}
534538

535539
return formattedText;
536540
}
537541

542+
// In case of the special params pattern (x, y, arg1, ...) we base the argument display on an expanded argument list, matching Excel's behaviour,
543+
// and the magic expansion in the function wizard.
544+
// Thanks to @amibar for figuring this out.
545+
// NOTE: We might need to get the whole formula, the current location (or prefix) and the currentArgIndex to implement Excel's behaviour for params parameters.
546+
// Usually just having the prefix is OK, but in case we have the formula: F(params object[] args) and we write in the formula editor =F(1,2,3,4,5,6,7)
547+
// and then we move the cursor to point on the second argument, our current implementation will shorten its text and omit any argument after the 3rd argument.
548+
// But Excel will keep showing the vurtual argument list corresponding to the full formula.
549+
// There is no technical problem in getting the full formula - PenHelper will give us the required info - but tracking this throughout the IntelliSense state
550+
// affects the code in a lot of places, and the benefits seem small, particularly in this case of quirky Excel behaviour.
551+
List<FunctionInfo.ArgumentInfo> GetExpandedArgumentList(FunctionInfo functionInfo, int currentArgIndex)
552+
{
553+
// Note: Using params for the last argument
554+
if (functionInfo.ArgumentList.Count > 1 &&
555+
functionInfo.ArgumentList[functionInfo.ArgumentList.Count - 1].Name == "..." &&
556+
functionInfo.ArgumentList[functionInfo.ArgumentList.Count - 2].Name.EndsWith("1") && // Note: Need both the Arg1 and the ... to trigger the expansion in the function wizard?
557+
currentArgIndex >= functionInfo.ArgumentList.Count - 2)
558+
{
559+
var paramsIndex = functionInfo.ArgumentList.Count - 2;
560+
561+
// Take the last named argument and omit the "1" that the registration added
562+
var paramsDesc = functionInfo.ArgumentList[paramsIndex].Description;
563+
string paramsBaseName = functionInfo.ArgumentList[paramsIndex].Name.TrimEnd('1');
564+
int currentParamsArgIndex = currentArgIndex - paramsIndex;
565+
566+
// Omit last two entries ("Arg1" and "...") from the original argument list
567+
var newList = new List<FunctionInfo.ArgumentInfo>(functionInfo.ArgumentList.Take(paramsIndex));
568+
// Now if we're at Arg3 (currentParamsIndex=2) then add "[Arg1],[Arg2],[Arg3],[Arg4],..."
569+
for (int i = 1; i <= currentParamsArgIndex + 1; i++)
570+
{
571+
newList.Add(new FunctionInfo.ArgumentInfo { Name = $"[{paramsBaseName + i}]", Description = paramsDesc });
572+
}
573+
newList.Add(new FunctionInfo.ArgumentInfo { Name = "...", Description = paramsDesc });
574+
575+
return newList;
576+
}
577+
else
578+
{
579+
// No problems - just return the real argumentlist
580+
return functionInfo.ArgumentList;
581+
}
582+
}
583+
538584
TextLine GetArgumentDescriptionOrNull(FunctionInfo.ArgumentInfo argumentInfo)
539585
{
540586
if (string.IsNullOrEmpty(argumentInfo.Description))

0 commit comments

Comments
 (0)