Skip to content

Commit ae98a48

Browse files
daxian-dbwjoeyaiello
authored andcommitted
Merge withdrawn RFC for "A Design of the Command-line Suggestion Infrastructure" (#123)
* Command-line Suggestion Infrastructure * Withdraw ML suggestion RFC
1 parent 7c0ece5 commit ae98a48

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
RFC: RFC
3+
Author: Dongbo Wang
4+
Status: Withdrawn
5+
SupercededBy: N/A
6+
Version: 1.0
7+
Area: Engine
8+
Comments Due: April 30th, 2018
9+
Plan to implement: No
10+
---
11+
12+
# Command-line Suggestion Infrastructure
13+
14+
This RFC is to propose a design of command-line suggestion infrastructure in PowerShell engine.
15+
16+
## Motivation
17+
18+
[PowerShell in Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/cloud-shell/overview) targets a very specific PowerShell use scenario -- Azure resource management.
19+
It is an Azure service, which means it is possible to collect telemetry about how people use the shell. Given these two facts,
20+
it is interesting to see whether ML can be leveraged to study the telemetry data within the targeted scenario,
21+
and provide useful command-line suggestions in the cloud shell based on the user input.
22+
23+
It should be pointed out that, the command-line suggestion is different from tab completion in both purpose and its inner working.
24+
From the perspective of purpose,
25+
tab completion targets a specific syntactic part of the typed input, such as a parameter name or a member,
26+
while command-line suggestion targets the whole input string and gives suggestions like how a search engine reacts to the user input.
27+
From the perspective of inner working,
28+
tab completion mainly depend on inference within the runtime,
29+
while command-line suggestion depends on studying the pattern of the history inputs.
30+
31+
Of course, in order for PowerShell cloud shell to do this, basic infrastructure support is required in both the PowerShell engine and host.
32+
PowerShell itself should make it easy to plug in a suggestion engine via a module, as well as present the suggestion results to the user.
33+
With this support, the cloud shell can focus on the design of the suggestion engine,
34+
and enable it in the could environment by simply loading the suggestion engine as a module.
35+
36+
## Specification
37+
38+
### Interface with Suggestion Engine
39+
40+
The proposal is to have a similar infrastructure as the tab completion today.
41+
A cmdlet named `CommandLineSuggestion` will be used as the interface between PowerShell and a suggestion engine.
42+
The suggestion engine could be completely PowerShell-agnostic.
43+
To turn it into a module that works with PowerShell,
44+
you just need to have the cmdlet `CommandLineSuggestion` as a thin wrapper over its suggestion APIs.
45+
46+
The syntax of `CommandLineSuggestion` looks as follows:
47+
48+
```powershell
49+
CommandLineSuggestion [-InputScript] <string> [-HistoryInput] <string[]> [-Async] [<CommonParameters>]
50+
```
51+
52+
- The parameter `-InputScript` is mandatory, which takes the user input for suggestions.
53+
- The parameter `-HistoryInput` can be mandatory or optional, which takes the relevant history inputs as a context for the suggestion.
54+
Given the privacy concerns, only the history from the current local/remote session is passed to the cmdlet by PowerShell,
55+
which can be retrieved easily with `Get-History`.
56+
This may seem no much value due to the limitation of the data set,
57+
but it won't be a problem in cloud shell as the telemetry will provide much richer context for the suggestion engine to work.
58+
From that perspective, we can see the history context is not necessarily needed by all suggestion engines,
59+
and therefore, a suggestion engine module can indicate whether or not it needs this information by making `-HistoryInput` mandatory or optional.
60+
In case `-HistoryInput` is optional, PowerShell won't bother to collect the history inputs.
61+
- The parameter `Async` is optional, which instructs the cmdlet to run synchronously or asynchronously.
62+
When running synchronously, the cmdlet returns a collection of strings as the suggestion results.
63+
When running asynchronously, the cmdlet returns a `Task<Collection<string>>` that represents a already started asynchronous operation.
64+
65+
When running in a remote session, the tab completion calls `TabExpansion2` in the remote Runspace to get the completion results.
66+
This is necessary for tab completion because inference needs to happen in the right context.
67+
However, this is not necessary for command-line suggestion.
68+
`CommandLineSuggestion` will always be invoked from the default local Runspace (`[runspace]::DefaultRunspace`),
69+
so the task-based asynchronous behavior of the cmdlet is guaranteed to work properly
70+
(serialization and de-serialization would break the async behavior if invoking the cmdlet in a remote Runspace).
71+
When `-HistoryInput` is mandatory, PowerShell will collect the history from the default local Runspace and the remote Runspace (if there is one),
72+
and then pass the history context along when invoking `CommandLineSuggestion`.
73+
74+
### Interface with UI Component
75+
76+
Two static method will be exposed to interact with the UI component. They look as follows:
77+
78+
```c#
79+
public static Collection<string> SuggestInput(string input, powershell powershell);
80+
public static Task<Collection<string>> SuggestInput(string input, powershell powershell);
81+
```
82+
83+
- The first method is synchronous, where `CommandLineSuggestion` is invoked without `-Async`.
84+
- The second method is asynchronous, where `CommandLineSuggestion` is invoked with `-Async`.
85+
PowerShell will make sure the `Task<Collection<string>>` object is started before returning it from this method
86+
(`CommandLineSuggestion` should have started the task before writing it out).
87+
- The `powershell` parameter indicates the current active Runspace of the host.
88+
This parameter is needed to get the history from the current session.
89+
When the host is in `Enter-PSSession`, `powershell` points to the remote runspace.
90+
So if it's needed, PowerShell can get the history from the remote Runspace as well as from the default local Runspace.
91+
92+
### Simple Local Experience
93+
94+
A simple local experience needs to be implemented to verify the design and show people what it looks like.
95+
96+
#### Suggestion Engine
97+
98+
To prove the concept, a simple local suggestion engine needs to be implemented.
99+
It provides suggestions only based on the passed in history context with a string proximity algorithm, such as
100+
[Levenshtein distance](https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance) or
101+
[Dice's coefficient](https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Dice%27s_coefficient).
102+
By using the string proximity algorithm, it can calculate the proximity rate between each history command-line and the current input,
103+
and return suggestions based on the proximity rates.
104+
105+
#### Update PSReadline
106+
107+
To prove the concept, we need to update `PSReadline` to interact with the `SuggestInput` APIs and render suggestions on the host.
108+
The rudimentary idea is to borrow and alter the existing UI experience of `Ctrl+Space` in `PSReadline` 2.0,
109+
where completion options show up as a table and you can move cursor around to choose what you want.
110+
111+
- A custom key binding will be used to trigger the suggestion,
112+
and returned suggestions will be shown in a single-column table, ordered by the proximity rate of each suggestion.
113+
Similarly, a user can move the cursor with `Up` and `Down` arrow keys and confirm an option with the `Enter` key.
114+
- For each returned suggestion string, the words that appear in the input will be rendered with green color,
115+
so that it's easy for user to see the what matches the input and what doesn't.
116+
- Once the suggestions are shown up, you can continue typing and the suggestion list will be filtered based on the new input,
117+
which may result in the rendered suggestions to be reordered or shrunk.
118+
Note that the filtering doesn't call `SuggestInput` again.
119+
Instead, it applies a **filtering method** on the previously returned suggestions.
120+
- After typing more on the host, if you think the filtered suggestions are not relevant anymore,
121+
you can press the key binding again to trigger another suggestion based on the current input.
122+
123+
The **filtering method** should ideally be returned by the suggestion engine as a delegate along with the suggestion results.
124+
This is currently not enforced in the interface contacts we defined above.
125+
However, we can change the interface contracts if the filtering method proves to be valuable.
126+
For this simple local experience,
127+
PowerShell will provide a filtering delegate that always depends on the string proximity algorithm to filter the given suggestions.
128+
129+
PowerShell could provide some utility methods to help the UI components,
130+
such as a method to find all common words between two strings.
131+
132+
### Cloud Shell Experience
133+
134+
The goal of this infrastructure design is to allow a custom suggestion engine to be completely self-contained and PowerShell-agnostic.
135+
The cloud shell team can design the suggestion engine without having PowerShell in mind.
136+
All they need is to provide the synchronous and the task-based asynchronous APIs for getting suggestions.
137+
Then, it can be easily plug in to PowerShell by wrapping their APIs in the cmdlet `CommandLineSuggestion`.
138+
139+
## Alternate Proposals and Considerations
140+
141+
A C# interface between PowerShell and suggestion engine was considered initially.
142+
It's in the form of a C# interface or abstract class,
143+
and a suggestion engine needs to implement them to integrate with PowerShell.
144+
145+
Then I found it's hard to register and un-register a suggestion engine when loading and unloading a module.
146+
Using a cmdlet as the interface makes things easy because the registration and un-registration is already taken care of by PowerShell module.

0 commit comments

Comments
 (0)