diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Intellisense/SuggestionHandlers/FunctionRecordNameSuggestionHandler.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Intellisense/SuggestionHandlers/FunctionRecordNameSuggestionHandler.cs index 6460fde8d1..db3bc4f83f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Intellisense/SuggestionHandlers/FunctionRecordNameSuggestionHandler.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Intellisense/SuggestionHandlers/FunctionRecordNameSuggestionHandler.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using Microsoft.PowerFx.Core.Binding.BindInfo; using Microsoft.PowerFx.Core.Functions; @@ -152,9 +153,17 @@ private static bool TryGetParentRecordFieldType(DType aggregateType, TexlNode cu internal static bool AddAggregateSuggestions(DType aggregateType, IntellisenseData.IntellisenseData intellisenseData, int cursorPos) { var suggestionsAdded = false; + var parentRecordNode = intellisenseData.CurNode.Parent as RecordNode; + var alreadyUsedFields = parentRecordNode?.Ids.Select(id => id.Name).ToImmutableHashSet(); foreach (var tName in aggregateType.GetNames(DPath.Root).Where(param => !param.Type.IsError)) { var usedName = tName.Name; + + if (alreadyUsedFields?.Contains(usedName) == true) + { + continue; + } + if (DType.TryGetDisplayNameForColumn(aggregateType, usedName, out var maybeDisplayName)) { usedName = new DName(maybeDisplayName); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests/IntellisenseTests/SuggestTest.cs b/src/tests/Microsoft.PowerFx.Core.Tests/IntellisenseTests/SuggestTest.cs index 4f3da5d03a..8bdc7f9bca 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests/IntellisenseTests/SuggestTest.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests/IntellisenseTests/SuggestTest.cs @@ -168,8 +168,8 @@ private string[] SuggestStrings(string expression, PowerFxConfig config, Culture [InlineData("[@In|]", "ErrorKind")] // FunctionRecordNameSuggestionHandler - [InlineData("Error({Kin|d:0})", "Kind:")] - [InlineData("Error({|Kind:0, Test:\"\"})", "Kind:", "Test:")] + [InlineData("Error({Kin|d:0})")] + [InlineData("Error({|Kind:0, Test:\"\"})")] // ErrorNodeSuggestionHandler [InlineData("ForAll([0],`|", "ThisRecord", "Value")] @@ -493,7 +493,7 @@ public void SuggestUser(string expression, params string[] expected) [Theory] [InlineData("{|", "output1:", "output2:")] - [InlineData("{output1: 1, |", "output1:", "output2:")] + [InlineData("{output1: 1, |", "output2:")] // We do not suggest nested type, as this can explode if type is DV. [InlineData("{output1: {|")] diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests/InterpreterSuggestTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests/InterpreterSuggestTests.cs index b6fcaa702a..214da2e6bd 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests/InterpreterSuggestTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests/InterpreterSuggestTests.cs @@ -274,21 +274,42 @@ public void TestArgSuggestion(string expression, params string[] expectedSuggest "field1:")] [InlineData( "RecordInputTest( {field1 : 1}, \"test\", {|", - "id:", + "id:", + "name:")] + + // do not repeat already used fields. + [InlineData( + "RecordInputTest( {field1 : 2}, \"test\", { id: 1, |", "name:")] + + [InlineData( + "RecordInputTest( {field1 : 2}, \"test\", { name: \"test\", |", + "id:")] + [InlineData( - "RecordInputTest( {field1 : 2}, \"test\", { id: 1, name: \"test\"}, {|", + "RecordInputTest( {field1 : 2}, \"test\", { id: 1, name:\"test name\", |}")] + + [InlineData( + "RecordInputTest( {field1 : 2}, \"test\", { id: 1, name: \"test\"}, {|", "nested:", "nested2:")] // nested record field. [InlineData( - "RecordInputTest( {field1 : 3}, \"test\", { id: 1, name: \"test\"}, { nested:{|", + "RecordInputTest( {field1 : 3}, \"test\", { id: 1, name: \"test\"}, { nested:{|", "field1:")] [InlineData( - "RecordInputTest( {field1 : 4}, \"test\", { id: 1, name: \"test\"}, { nested2:{|", - "id:", + "RecordInputTest( {field1 : 4}, \"test\", { id: 1, name: \"test\"}, { nested2:{|", + "id:", "name:")] + + // do not repeat already used fields. + [InlineData( + "RecordInputTest( {field1 : 4}, \"test\", { id: 1, name: \"test\"}, { nested2:{ id: 2, |", + "name:")] + [InlineData( + "RecordInputTest( {field1 : 4}, \"test\", { id: 1, name: \"test\"}, { nested2:{ id: 2, name: \"test\", |")] + [InlineData( "RecordInputTest( {field1 : 3}, \"test\", { id: 1, name: \"test\"}, { nested:{ field1: 1}, nested2: {|", "id:",