Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ internal List<CompletionResult> GetResults(PowerShell powerShell, out int replac
completionContext.ExecutionContext.LanguageMode = PSLanguageMode.ConstrainedLanguage;
}

return GetResultHelper(completionContext, out replacementIndex, out replacementLength, false);
return GetResultHelper(completionContext, out replacementIndex, out replacementLength);
}
finally
{
Expand All @@ -398,7 +398,7 @@ internal List<CompletionResult> GetResults(PowerShell powerShell, out int replac
}
}

internal List<CompletionResult> GetResultHelper(CompletionContext completionContext, out int replacementIndex, out int replacementLength, bool isQuotedString)
internal List<CompletionResult> GetResultHelper(CompletionContext completionContext, out int replacementIndex, out int replacementLength)
{
replacementIndex = -1;
replacementLength = -1;
Expand Down Expand Up @@ -434,16 +434,12 @@ internal List<CompletionResult> GetResultHelper(CompletionContext completionCont
return result;
}

result = GetResultForIdentifier(completionContext, ref replacementIndex, ref replacementLength, isQuotedString);
result = GetResultForIdentifier(completionContext, ref replacementIndex, ref replacementLength);
}

break;

case TokenKind.Parameter:
// When it's the content of a quoted string, we only handle variable/member completion
if (isQuotedString)
break;

completionContext.WordToComplete = tokenAtCursor.Text;
var cmdAst = lastAst.Parent as CommandAst;
if (lastAst is StringConstantExpressionAst && cmdAst != null && cmdAst.CommandElements.Count == 1)
Expand Down Expand Up @@ -491,10 +487,6 @@ internal List<CompletionResult> GetResultHelper(CompletionContext completionCont
break;

case TokenKind.Comment:
// When it's the content of a quoted string, we only handle variable/member completion
if (isQuotedString)
break;

completionContext.WordToComplete = tokenAtCursor.Text;
result = CompletionCompleters.CompleteComment(completionContext, ref replacementIndex, ref replacementLength);
break;
Expand Down Expand Up @@ -527,7 +519,7 @@ internal List<CompletionResult> GetResultHelper(CompletionContext completionCont
return CompletionCompleters.CompleteIndexExpression(completionContext, indexExpressionAst.Target);
}

result = GetResultForString(completionContext, ref replacementIndex, ref replacementLength, isQuotedString);
result = GetResultForString(completionContext, ref replacementIndex, ref replacementLength);
break;

case TokenKind.RBracket:
Expand Down Expand Up @@ -839,8 +831,7 @@ internal List<CompletionResult> GetResultHelper(CompletionContext completionCont

bool skipAutoCompleteForCommandCall = isCursorLineEmpty && !isLineContinuationBeforeCursor;
bool lastAstIsExpressionAst = lastAst is ExpressionAst;
if (!isQuotedString &&
!skipAutoCompleteForCommandCall &&
if (!skipAutoCompleteForCommandCall &&
(lastAst is CommandParameterAst || lastAst is CommandAst ||
(lastAstIsExpressionAst && lastAst.Parent is CommandAst) ||
(lastAstIsExpressionAst && lastAst.Parent is CommandParameterAst) ||
Expand Down Expand Up @@ -879,7 +870,7 @@ internal List<CompletionResult> GetResultHelper(CompletionContext completionCont
replacementLength = completionContext.ReplacementLength;
}
}
else if (!isQuotedString)
else
{
//
// Handle completion of empty line within configuration statement
Expand Down Expand Up @@ -1778,111 +1769,50 @@ private static List<CompletionResult> GetResultForEnumPropertyValueOfDSCResource
return result;
}

private List<CompletionResult> GetResultForString(CompletionContext completionContext, ref int replacementIndex, ref int replacementLength, bool isQuotedString)
private static List<CompletionResult> GetResultForString(CompletionContext completionContext, ref int replacementIndex, ref int replacementLength)
{
// When it's the content of a quoted string, we only handle variable/member completion
if (isQuotedString) { return null; }

var tokenAtCursor = completionContext.TokenAtCursor;
var lastAst = completionContext.RelatedAsts.Last();

List<CompletionResult> result = null;
var expandableString = lastAst as ExpandableStringExpressionAst;
var constantString = lastAst as StringConstantExpressionAst;
if (constantString == null && expandableString == null) { return null; }

string strValue = constantString != null ? constantString.Value : expandableString.Value;
StringConstantType strType = constantString != null ? constantString.StringConstantType : expandableString.StringConstantType;
string subInput = null;

bool shouldContinue;
result = GetResultForEnumPropertyValueOfDSCResource(completionContext, strValue, ref replacementIndex, ref replacementLength, out shouldContinue);
List<CompletionResult> result = GetResultForEnumPropertyValueOfDSCResource(completionContext, strValue, ref replacementIndex, ref replacementLength, out shouldContinue);
if (!shouldContinue || (result != null && result.Count > 0))
{
return result;
}

if (strType == StringConstantType.DoubleQuoted)
{
var match = Regex.Match(strValue, @"(\$[\w\d]+\.[\w\d\*]*)$");
if (match.Success)
{
subInput = match.Groups[1].Value;
}
else if ((match = Regex.Match(strValue, @"(\[[\w\d\.]+\]::[\w\d\*]*)$")).Success)
{
subInput = match.Groups[1].Value;
}
}
var commandElementAst = lastAst as CommandElementAst;
string wordToComplete =
CompletionCompleters.ConcatenateStringPathArguments(commandElementAst, string.Empty, completionContext);

// Handle variable/member completion
if (subInput != null)
if (wordToComplete != null)
{
int stringStartIndex = tokenAtCursor.Extent.StartScriptPosition.Offset;
int cursorIndexInString = _cursorPosition.Offset - stringStartIndex - 1;
if (cursorIndexInString >= strValue.Length)
cursorIndexInString = strValue.Length;

var analysis = new CompletionAnalysis(_ast, _tokens, _cursorPosition, _options);
var subContext = analysis.CreateCompletionContext(completionContext.TypeInferenceContext);
completionContext.WordToComplete = wordToComplete;

var subResult = analysis.GetResultHelper(subContext, out int subReplaceIndex, out _, true);

if (subResult != null && subResult.Count > 0)
// Handle scenarios like this: cd 'c:\windows\win'<tab>
if (lastAst.Parent is CommandAst || lastAst.Parent is CommandParameterAst)
{
result = new List<CompletionResult>();
replacementIndex = stringStartIndex + 1 + (cursorIndexInString - subInput.Length);
replacementLength = subInput.Length;
ReadOnlySpan<char> prefix = subInput.AsSpan(0, subReplaceIndex);

foreach (CompletionResult entry in subResult)
{
string completionText = string.Concat(prefix, entry.CompletionText.AsSpan());
if (entry.ResultType == CompletionResultType.Property)
{
completionText = TokenKind.DollarParen.Text() + completionText + TokenKind.RParen.Text();
}
else if (entry.ResultType == CompletionResultType.Method)
{
completionText = TokenKind.DollarParen.Text() + completionText;
}

completionText += "\"";
result.Add(new CompletionResult(completionText, entry.ListItemText, entry.ResultType, entry.ToolTip));
}
result = CompletionCompleters.CompleteCommandArgument(completionContext);
replacementIndex = completionContext.ReplacementIndex;
replacementLength = completionContext.ReplacementLength;
}
}
else
{
var commandElementAst = lastAst as CommandElementAst;
string wordToComplete =
CompletionCompleters.ConcatenateStringPathArguments(commandElementAst, string.Empty, completionContext);

if (wordToComplete != null)
// Handle scenarios like this: "c:\wind"<tab>. Treat the StringLiteral/StringExpandable as path/command
else
{
completionContext.WordToComplete = wordToComplete;
// Handle path/commandname completion for quoted string
result = new List<CompletionResult>(CompletionCompleters.CompleteFilename(completionContext));

// Handle scenarios like this: cd 'c:\windows\win'<tab>
if (lastAst.Parent is CommandAst || lastAst.Parent is CommandParameterAst)
// Try command name completion only if the text contains '-'
if (wordToComplete.Contains('-'))
{
result = CompletionCompleters.CompleteCommandArgument(completionContext);
replacementIndex = completionContext.ReplacementIndex;
replacementLength = completionContext.ReplacementLength;
}
// Handle scenarios like this: "c:\wind"<tab>. Treat the StringLiteral/StringExpandable as path/command
else
{
// Handle path/commandname completion for quoted string
result = new List<CompletionResult>(CompletionCompleters.CompleteFilename(completionContext));

// Try command name completion only if the text contains '-'
if (wordToComplete.Contains('-'))
var commandNameResult = CompletionCompleters.CompleteCommand(completionContext);
if (commandNameResult != null && commandNameResult.Count > 0)
{
var commandNameResult = CompletionCompleters.CompleteCommand(completionContext);
if (commandNameResult != null && commandNameResult.Count > 0)
{
result.AddRange(commandNameResult);
}
result.AddRange(commandNameResult);
}
}
}
Expand Down Expand Up @@ -2000,7 +1930,7 @@ private static List<CompletionResult> GetResultForIdentifierInConfiguration(
return results;
}

private static List<CompletionResult> GetResultForIdentifier(CompletionContext completionContext, ref int replacementIndex, ref int replacementLength, bool isQuotedString)
private static List<CompletionResult> GetResultForIdentifier(CompletionContext completionContext, ref int replacementIndex, ref int replacementLength)
{
List<CompletionResult> result = null;
var tokenAtCursor = completionContext.TokenAtCursor;
Expand Down Expand Up @@ -2148,9 +2078,6 @@ private static List<CompletionResult> GetResultForIdentifier(CompletionContext c
}
}

// When it's the content of a quoted string, we only handle variable/member completion
if (isQuotedString) { return result; }

// Handle the StringExpandableToken;
var strToken = tokenAtCursor as StringExpandableToken;
if (strToken != null && strToken.NestedTokens != null && strConst != null)
Expand Down Expand Up @@ -2220,8 +2147,6 @@ private static List<CompletionResult> GetResultForIdentifier(CompletionContext c
// When it's the content of a quoted string, we only handle variable/member completion
if (isSingleDash)
{
if (isQuotedString) { return result; }

var res = CompletionCompleters.CompleteCommandParameter(completionContext);
if (res.Count != 0)
{
Expand Down Expand Up @@ -2327,9 +2252,6 @@ private static List<CompletionResult> GetResultForIdentifier(CompletionContext c
}
}

// When it's the content of a quoted string, we only handle variable/member completion
if (isQuotedString) { return result; }

bool needFileCompletion = false;
if (lastAst.Parent is FileRedirectionAst || CompleteAgainstSwitchFile(lastAst, completionContext.TokenBeforeCursor))
{
Expand Down