@@ -19,7 +19,8 @@ public partial class CompletionPredictor : ICommandPredictor, IDisposable
19
19
"ForEach-Object" ,
20
20
"?" ,
21
21
"where" ,
22
- "Where-Object"
22
+ "Where-Object" ,
23
+ "cd" ,
23
24
} ;
24
25
25
26
internal CompletionPredictor ( string guid )
@@ -62,33 +63,59 @@ public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContex
62
63
return default ;
63
64
}
64
65
66
+ return GetFromTabCompletion ( context , cancellationToken ) ;
67
+ }
68
+
69
+ private SuggestionPackage GetFromTabCompletion ( PredictionContext context , CancellationToken cancellationToken )
70
+ {
65
71
// Call into PowerShell tab completion to get completion results.
66
72
// The runspace may be held by another call, or the call may take too long and exceed the timeout.
67
73
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 )
69
75
{
70
76
return default ;
71
77
}
72
78
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 ;
78
84
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 ) ;
81
87
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 )
83
95
{
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 ;
86
108
}
87
109
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
+ }
89
116
}
90
117
91
- return default ;
118
+ return list is null ? default : new SuggestionPackage ( list ) ;
92
119
}
93
120
94
121
private CommandCompletion ? GetCompletionResults ( Ast inputAst , IReadOnlyCollection < Token > inputTokens , IScriptPosition cursorPosition )
0 commit comments