Skip to content

Commit cb361ea

Browse files
ArmaanMcleodSIRMARGIN
authored andcommitted
Add single/double quote support for Join-String Argument Completer (PowerShell#25283)
1 parent b5e335b commit cb361ea

5 files changed

Lines changed: 416 additions & 81 deletions

File tree

src/Microsoft.PowerShell.Commands.Utility/commands/utility/Join-String.cs

Lines changed: 85 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public sealed class JoinStringCommand : PSCmdlet
4141
/// Gets or sets the delimiter to join the output with.
4242
/// </summary>
4343
[Parameter(Position = 1)]
44-
[ArgumentCompleter(typeof(JoinItemCompleter))]
44+
[ArgumentCompleter(typeof(SeparatorArgumentCompleter))]
4545
[AllowEmptyString]
4646
public string Separator
4747
{
@@ -79,7 +79,7 @@ public string Separator
7979
/// Gets or sets a format string that is applied to each input object.
8080
/// </summary>
8181
[Parameter(ParameterSetName = "Format")]
82-
[ArgumentCompleter(typeof(JoinItemCompleter))]
82+
[ArgumentCompleter(typeof(FormatStringArgumentCompleter))]
8383
public string FormatString { get; set; }
8484

8585
/// <summary>
@@ -160,79 +160,100 @@ protected override void EndProcessing()
160160
}
161161
}
162162

163-
[SuppressMessage(
164-
"Microsoft.Performance",
165-
"CA1812:AvoidUninstantiatedInternalClasses",
166-
Justification = "Class is instantiated through late-bound reflection")]
167-
internal class JoinItemCompleter : IArgumentCompleter
163+
/// <summary>
164+
/// Provides completion for the Separator parameter of the Join-String cmdlet.
165+
/// </summary>
166+
public sealed class SeparatorArgumentCompleter : IArgumentCompleter
168167
{
169-
public IEnumerable<CompletionResult> CompleteArgument(
170-
string commandName,
171-
string parameterName,
172-
string wordToComplete,
173-
CommandAst commandAst,
174-
IDictionary fakeBoundParameters)
175-
{
176-
switch (parameterName)
177-
{
178-
case "Separator": return CompleteSeparator(wordToComplete);
179-
case "FormatString": return CompleteFormatString(wordToComplete);
180-
}
181-
182-
return null;
183-
}
168+
private static readonly string NewLineText =
169+
#if UNIX
170+
"`n";
171+
#else
172+
"`r`n";
173+
#endif
184174

185-
private static IEnumerable<CompletionResult> CompleteFormatString(string wordToComplete)
175+
private static readonly Dictionary<string, (string Tooltip, string ListItemText)> s_separatorMappings = new(capacity: 7)
186176
{
187-
var res = new List<CompletionResult>();
188-
void AddMatching(string completionText)
189-
{
190-
if (completionText.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase))
191-
{
192-
res.Add(new CompletionResult(completionText));
193-
}
194-
}
177+
{ ",", (TabCompletionStrings.SeparatorCommaToolTip, "Comma") },
178+
{ ", ", (TabCompletionStrings.SeparatorCommaSpaceToolTip, "Comma-Space") },
179+
{ ";", (TabCompletionStrings.SeparatorSemiColonToolTip, "Semi-Colon") },
180+
{ "; ", (TabCompletionStrings.SeparatorSemiColonSpaceToolTip, "Semi-Colon-Space") },
181+
{ NewLineText, (StringUtil.Format(TabCompletionStrings.SeparatorNewlineToolTip, NewLineText), "Newline") },
182+
{ "-", (TabCompletionStrings.SeparatorDashToolTip, "Dash") },
183+
{ " ", (TabCompletionStrings.SeparatorSpaceToolTip, "Space") },
184+
};
195185

196-
AddMatching("'[{0}]'");
197-
AddMatching("'{0:N2}'");
198-
AddMatching("\"`r`n `${0}\"");
199-
AddMatching("\"`r`n [string] `${0}\"");
186+
private static readonly IEnumerable<string> s_separatorValues = s_separatorMappings.Keys;
200187

201-
return res;
202-
}
203-
204-
private IEnumerable<CompletionResult> CompleteSeparator(string wordToComplete)
205-
{
206-
var res = new List<CompletionResult>(10);
188+
private static string GetSeparatorToolTip(string separator)
189+
=> s_separatorMappings.TryGetValue(separator, out var mapping)
190+
? mapping.Tooltip
191+
: separator;
207192

208-
void AddMatching(string completionText, string listText, string toolTip)
209-
{
210-
if (completionText.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase))
211-
{
212-
res.Add(new CompletionResult(completionText, listText, CompletionResultType.ParameterValue, toolTip));
213-
}
214-
}
193+
private static string GetSeparatorListItemText(string separator)
194+
=> s_separatorMappings.TryGetValue(separator, out var mapping)
195+
? mapping.ListItemText
196+
: separator;
215197

216-
AddMatching("', '", "Comma-Space", "', ' - Comma-Space");
217-
AddMatching("';'", "Semi-Colon", "';' - Semi-Colon ");
218-
AddMatching("'; '", "Semi-Colon-Space", "'; ' - Semi-Colon-Space");
219-
AddMatching($"\"{NewLineText}\"", "Newline", $"{NewLineText} - Newline");
220-
AddMatching("','", "Comma", "',' - Comma");
221-
AddMatching("'-'", "Dash", "'-' - Dash");
222-
AddMatching("' '", "Space", "' ' - Space");
223-
return res;
224-
}
198+
/// <summary>
199+
/// Returns completion results for Separator parameter.
200+
/// </summary>
201+
/// <param name="commandName">The command name.</param>
202+
/// <param name="parameterName">The parameter name.</param>
203+
/// <param name="wordToComplete">The word to complete.</param>
204+
/// <param name="commandAst">The command AST.</param>
205+
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
206+
/// <returns>List of Completion Results.</returns>
207+
public IEnumerable<CompletionResult> CompleteArgument(
208+
string commandName,
209+
string parameterName,
210+
string wordToComplete,
211+
CommandAst commandAst,
212+
IDictionary fakeBoundParameters)
213+
=> CompletionHelpers.GetMatchingResults(
214+
wordToComplete,
215+
possibleCompletionValues: s_separatorValues,
216+
listItemTextMapping: GetSeparatorListItemText,
217+
toolTipMapping: GetSeparatorToolTip,
218+
resultType: CompletionResultType.ParameterValue);
219+
}
225220

226-
public string NewLineText
221+
/// <summary>
222+
/// Provides completion for the FormatString parameter of the Join-String cmdlet.
223+
/// </summary>
224+
public sealed class FormatStringArgumentCompleter : IArgumentCompleter
225+
{
226+
private static readonly IReadOnlyList<string> s_formatStringValues = new List<string>(capacity: 4)
227227
{
228-
get
229-
{
228+
"[{0}]",
229+
"{0:N2}",
230230
#if UNIX
231-
return "`n";
231+
"`n `${0}",
232+
"`n [string] `${0}",
232233
#else
233-
return "`r`n";
234+
"`r`n `${0}",
235+
"`r`n [string] `${0}",
234236
#endif
235-
}
236-
}
237+
};
238+
239+
/// <summary>
240+
/// Returns completion results for FormatString parameter.
241+
/// </summary>
242+
/// <param name="commandName">The command name.</param>
243+
/// <param name="parameterName">The parameter name.</param>
244+
/// <param name="wordToComplete">The word to complete.</param>
245+
/// <param name="commandAst">The command AST.</param>
246+
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
247+
/// <returns>List of Completion Results.</returns>
248+
public IEnumerable<CompletionResult> CompleteArgument(
249+
string commandName,
250+
string parameterName,
251+
string wordToComplete,
252+
CommandAst commandAst,
253+
IDictionary fakeBoundParameters)
254+
=> CompletionHelpers.GetMatchingResults(
255+
wordToComplete,
256+
possibleCompletionValues: s_formatStringValues,
257+
matchStrategy: CompletionHelpers.WildcardPatternEscapeMatch);
237258
}
238259
}

0 commit comments

Comments
 (0)