Skip to content

Commit f860b83

Browse files
authored
Allow argument completion on 'cd' (#20)
1 parent 752074b commit f860b83

File tree

1 file changed

+41
-14
lines changed

1 file changed

+41
-14
lines changed

src/CompletionPredictor.cs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public partial class CompletionPredictor : ICommandPredictor, IDisposable
1919
"ForEach-Object",
2020
"?",
2121
"where",
22-
"Where-Object"
22+
"Where-Object",
23+
"cd",
2324
};
2425

2526
internal CompletionPredictor(string guid)
@@ -62,33 +63,59 @@ public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContex
6263
return default;
6364
}
6465

66+
return GetFromTabCompletion(context, cancellationToken);
67+
}
68+
69+
private SuggestionPackage GetFromTabCompletion(PredictionContext context, CancellationToken cancellationToken)
70+
{
6571
// Call into PowerShell tab completion to get completion results.
6672
// The runspace may be held by another call, or the call may take too long and exceed the timeout.
6773
CommandCompletion? result = GetCompletionResults(context.InputAst, context.InputTokens, context.CursorPosition);
68-
if (result is null || cancellationToken.IsCancellationRequested)
74+
if (result is null || result.CompletionMatches.Count == 0 || cancellationToken.IsCancellationRequested)
6975
{
7076
return default;
7177
}
7278

73-
int count = result.CompletionMatches.Count;
74-
if (count > 0)
75-
{
76-
count = count > 10 ? 10 : count;
77-
var list = new List<PredictiveSuggestion>(count);
79+
int count = result.CompletionMatches.Count > 30 ? 30 : result.CompletionMatches.Count;
80+
List<PredictiveSuggestion>? list = null;
81+
82+
int replaceIndex = result.ReplacementIndex;
83+
string input = context.InputAst.Extent.Text;
7884

79-
string input = context.InputAst.Extent.Text;
80-
var head = result.ReplacementIndex == 0 ? ReadOnlySpan<char>.Empty : input.AsSpan(0, result.ReplacementIndex);
85+
ReadOnlySpan<char> head = replaceIndex == 0 ? ReadOnlySpan<char>.Empty : input.AsSpan(0, replaceIndex);
86+
ReadOnlySpan<char> diff = input.AsSpan(replaceIndex);
8187

82-
for (int i = 0; i < count; i++)
88+
for (int i = 0; i < count; i++)
89+
{
90+
CompletionResult completion = result.CompletionMatches[i];
91+
ReadOnlySpan<char> text = completion.CompletionText.AsSpan();
92+
string? suggestion = null;
93+
94+
switch (completion.ResultType)
8395
{
84-
var completion = result.CompletionMatches[i];
85-
list.Add(new PredictiveSuggestion(string.Concat(head, completion.CompletionText), completion.ToolTip));
96+
case CompletionResultType.ProviderItem or CompletionResultType.ProviderContainer when !diff.IsEmpty:
97+
// For local paths, if the input doesn't contain the prefix, then we stripe it from the suggestion.
98+
bool removeLocalPathPrefix =
99+
text.IndexOf(diff, StringComparison.OrdinalIgnoreCase) == 2 &&
100+
text[0] == '.' && text[1] == Path.DirectorySeparatorChar;
101+
ReadOnlySpan<char> newPart = removeLocalPathPrefix ? text.Slice(2) : text;
102+
suggestion = string.Concat(head, newPart);
103+
104+
break;
105+
106+
default:
107+
break;
86108
}
87109

88-
return new SuggestionPackage(list);
110+
suggestion ??= string.Concat(head, text);
111+
if (!string.Equals(input, suggestion, StringComparison.OrdinalIgnoreCase))
112+
{
113+
list ??= new List<PredictiveSuggestion>(count);
114+
list.Add(new PredictiveSuggestion(suggestion, completion.ToolTip));
115+
}
89116
}
90117

91-
return default;
118+
return list is null ? default : new SuggestionPackage(list);
92119
}
93120

94121
private CommandCompletion? GetCompletionResults(Ast inputAst, IReadOnlyCollection<Token> inputTokens, IScriptPosition cursorPosition)

0 commit comments

Comments
 (0)