Compare commits

...

4 Commits

Author SHA1 Message Date
Mike Griese
0c774d75e5 iterate on the Tasks spec a wee bit 2023-07-11 08:31:52 -05:00
Mike Griese
d6f053c828 add disclaimer 2023-07-10 14:50:18 -05:00
Mike Griese
c468ebb603 polish for review 2023-07-07 11:32:11 -05:00
Mike Griese
135e20f742 some thoughts 2023-05-31 06:01:31 -05:00
28 changed files with 2252 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
---
author: Mike Griese @zadjii-msft
created on: 2022-05-18
last updated: 2022-10-28
issue id: n/a
---
# Markdown Notebooks in the Terminal
> Note:
>
> This is a draft document. It's mainly ideating on a novel way of interacting
> with the Terminal. There's still a long gap between this and real shipping
> code, however.
>
> It is included with the remainder of my North Star docs, because it was always
> a part of that story. As we iterate on this protocol, we'll revise this doc
> with the final protocol.
## Abstract
"Terminal Notebooks" would allow developers to combine documentation and code in
a single file. Blocks of commands could be grouped logically together with their
output, for a more semantic experience. By leveraging markdown as a format, we
can expand upon an broad ecosystem of pre-existing content developers are
already familiar with.
## Background
Notebooks have risen to popularity in recent years as a way of combining both
code and documentation in a single experience. They enable users to seamlessly
write code, and execute it to see the output, write documentation on the code,
and share that with others. However, there's not really anything like notebooks
for generic commandline experiences.
There are, however, markdown files. Markdown has become a bit of a lingua franca
of the developer experience. It's used prominently on GitHub - the "homepage" of
any repo on GitHub is now typically a markdown file. This file will have all
sorts of documentation, and notably these READMEs are often filled with commands
that one can execute for this project. Downloading, installing its dependencies,
building and running the project, etc, all commands that are already listed
today in READMEs across the world.
It would be a major convenience for users to be able to just load a pre-rendered
markdown file directly into their terminal windows. These files already include
marked blocks of code which identify sets of commands for the command line. It
should be as simple as clicking a button to run these commands in the Terminal,
or even to run a whole file worth of commands automatically.
### Inspiration
[Jupyter notebooks] ([a Jupyter example]) served as the primary inspiration for
this feature. Another shoutout to [this comment on HackerNews], which inspired a
lot of brainstorming on this topic over the last year since it was posted.
Many initial brainstorms were focused on more notebook-like features in the
Terminal. For example, finding ways to create individual terminal blocks inline
with commands, where each input command and its output would be separated from
one another, possibly separated by some sort of text/rich markup. This seemed to
precipitate the need for a new file syntax to be authored, where we could save
commands as they were run. The Terminal would then open this new file type as a
set of terminal blocks each pre-populated with these saved commands.
However, this came with the drawback that projects which would like to leverage
this feature would have to author entirely new files, in a new syntax, just to
make use of this functionality. It seemed as though it was a niche enough UX
that it would be unlikely to broadly catch on.
The real inspiration here was that there's already a file type with broad
adoption that's already filled with commands like this. Markdown files. Take a
look at something like
[building.md](https://github.com/microsoft/terminal/blob/main/doc/building.md).
That file _already_ has a long set of commands for building the Terminal,
running tests, deploying, and various other helper scripts. Being able to
immediately leverage this existing ecosystem would undobtably lead to quicker
adoption.
### User Stories
* **A**: The user can perform some commandline action (like `wt open
README.md`), which opens a new pane in the Terminal, with the markdown file
rendered into that pane.
* **B**: Markdown panes have buttons next to code blocks that allow the text of
that block to be sent directly to the adjacent terminal as input.
* **C**: The user can press different buttons to run some subset of all the
commands in the file
- **C.1**: Run all the commands in this file
- **C.2**: Run all the commands from (the currently selected block) to the end
of the file
- **C.1**: Run all the commands from (the currently selected block) to the
next header. (e.g., run all the commands in this section of the doc.)
* **D**: The user can edit the contents of the markdown file directly in the
Terminal.
* **E**: The Terminal could be configured to automatically open a markdown file
when `cd`ing to a directory
* **F**: The command for opening a markdown file also supports opening files
from the web (e.g. directly from GitHub)
* **G**: Code blocks in the markdown file are automatically assigned
autoincrementing IDs. The user can perform an action (via keybinding, command
palette, whatever) to execute a command block from the file, based on it's
assigned ID.
* **H**: ...
## Solution Design
Below are two different structures that could be used for imlpementing notebooks
in the Terminal. These are **Side-by-side** notebooks, and **Inline** notebooks.
* **Side-by-side** notebooks consist of two panes - a standard terminal control
in one, and rendered markdown in the other.
* **Inline** notebooks are more like traditional notebooks, with the terminal
output rendered as a block within the rendered markdown content.
### Side-by-side notebooks
Opening Markdown side-by-side with the Terminal output is certainly a little
different than the way a notebook traditionally works. Notebooks typically have
the code in a block, with output inline, below the block. Blocks could also just
be dedicated to text, for documentation mixed between the code. The feature
proposed here is different from that, for sure. For this proposal, the Terminal
still exists side-by-side from the source markdown. Running commands from the
markdown text would then send the command as a string of input to the connected
terminal. This approach was elected over attempting to create artificial
boundaries between different blocks.
Oftentimes, the command line is a very stateful experience. Set some environment
variables, run some script, use the errorlevel from the previous command, etc.
Running each block in wholly separate console instances would likely not be
useful.
Additionally, finding the separation between command line input and its output,
and the separation between individual commands is not an entirely trivial
process. Should we try to separate out the command input line into one buffer,
then the output into another buffer sounds great on paper. Consider, however,
something like `cmd.exe`, which does not provide any sort of distinction between
its input line and its output. Or `python.exe`, as an interactive REPL, which
certainly doesn't tell the terminal the difference. How would we be able to
detect something like a multi-line command at the REPL?
By keeing the command blocks out-of-band from the terminal output, we keep the
familiar terminal experience. It acts just as you'd expect, with no additional
configuration on the user's side. The commands are something that are already
written down, just waiting for the user to run them. They could even be sent to
something that isn't necessarily a shell - like pasting a bit of configuration
into a text editor like `vim` or `emacs`. The commands in the markdown side are
just strings of text to send to the terminal side - nothing more.
### Inline notebooks
Is there a way to have a more traditional notebook experience, where the
terminal output is rendered as blocks within the markdown itself? I believe
there is, by making agressive use of the FTCS mark VT sequences. These are
sequences that enable identifying the parts of the buffer as a prompt, the
commandline, or the output. We can use these to pull out individual rows of the
buffer, and display them as miniature terminal controls within the notebook.
This involves a single terminal insance backing the entire notebook. When the
user runs a code block in the notebook, we'll `sendInput` the text to the
backing terminal the same as before. We'll then use the `FTCS_COMMAND_EXECUTED`
sequence to know where the actual start of the output of the command is. We'll
gather all output from that moment on, and tee that to a separate "front"
control, which we use as the display for the output of the command. We'll render
that "front" control inline with the rest of the markdown content, immediately
below the code block for that command.
> **Warning**: TODO! How do we want to handle interactive notebooks? Like, the user
> wants to run a command, and that creates a new block? We want to make sure
> the shell prompt is still just as interactive as ever.
> **Warning**: TODO! What about users who want to hit play on a whole bunch of
> blocks at once? We need a mechanism for queueing them, so that pressing play
> on two blocks waits till the first completes before starting the second.
> **Warning**: TODO! How do we deal with "page editing" multiple commands,
> interactively? Like, The user wants to interactively compose `cd
> c:\foo\`<kbd>tab</kbd>, then as a part of the same block do `dir | findstr
> *.json`? Does each command become it's own block, with a button to
> "concatenate" to the preceeding / following block?
### Windows Terminal implementation
The Terminal will allow for non-terminal content in a pane. This is something
that's been prototyped before, just needs a stronger justification for
finishing.
We'll leverage the Terminal's existing `sendInput` command to handle a lot of
this. That can be used to send keystrokes to the Terminal. Figuring out which
pane to send the `sendInput` command to might be a bit tricky. We'll need to
figure out what an action like that does when the active pane is not a terminal
pane.
The side-by-side experience is the easiest to implement today with the current
Terminal model. This wouldn't require any major changes to our `TermControl`,
which implements the actual terminal control within the Terminal app.
The inline experience would be more complicated - how do we
## UI/UX Design
### Side-by-side
![A rough mockup of what this feature might look like](img/mockup-000.png)
### Inline
![](img/inline-blocks-000.png)
## Tenents
<table>
<tr><td><strong>Accessibility</strong></td><td>
[comment]: # How will the proposed change impact accessibility for users of screen readers, assistive input devices, etc.
</td></tr>
<tr><td><strong>Security</strong></td><td>
[comment]: # How will the proposed change impact security?
Opening a file like this will _never_ auto-run commands. Commands must always be
intentionally interacted with, to provide a positive confirmation from the user
"yes, I intended to run `curl some.website.com/foo.txt`".
</td></tr>
<tr><td><strong>Reliability</strong></td><td>
[comment]: # Will the proposed change improve reliability? If not, why make the change?
</td></tr>
<tr><td><strong>Compatibility</strong></td><td>
[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
It's critically important that nothing about this feature be necessarily Windows
Terminal-dependent. These features shouldn't be powered by some new undocumented
escape sequence that only we support. They should NOT be powered by new Windows
APIs, especially not any extensions to the Console API. There's no reason other
terminals couldn't also implement similar functionality.
</td></tr>
<tr><td><strong>Performance, Power, and Efficiency</strong></td><td>
[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
</td></tr>
</table>
## Potential Issues
For rendering markdown, we'll either need:
* A way to display a WebView in a WinUI2 XAML Island
- This is something that's on the backlog currently for MUX 2.x. Theoretically
not too hard to add an `IInitializeWithWindow` to `WebView2` which should
enable XAML Islands, but needs more research.
* To migrate to WinUI 3
- In WinUI 3 I believe we should be able to get WebViews for free.
- We might still be a XAML Island in WinUI 3, which may complicate that.
* A C++ based method of rendering Markdown to UWP XAML
- There's a Windows Community Toolkit control for rendering to XAML currently,
but that is backed by C#, so we can't use that.
We'll also need the markdown rendering to be extensible, so that we can insert
"play" buttons alongside the blocks.
## Future considerations
### Tighter GitHub integration
GitHub already has the helpful "Open In GitHub" button for opening a repo in the
GitHub desktop client, or in Visual Studio.
![GitHub's "Clone, open or download" flyout](img/GitHub-open-with.png)
It'd be cool if there was a similar button for opening it up in the Terminal. It
could open the README immediately as a new tab, and then provide some sort of
InfoBar with a button that would allow the user to immediately clone the repo to
some location on their PC. This would likely need a protocol handler installed
by the Terminal to help connect the browser to the Terminal.
### Collapsible Blocks
One of the key features of notebooks is the ability to easily collapse regions
of the notebook. With the command output being out of band from the input of the
command, not as independent blocks, this becomes a bit trickier. To try and
reproduce a similar ability to collapse regions of the buffer, we'll look to
[Marks] in the terminal as a potential solution. The FinalTerm sequences allow a
client to mark up the region of the buffer that's the prompt, the command line,
and the output. Using those marks would provide an easy heuristic to allow users
to collapse the output of commands. These sequences however do require manual
configuration by the user, and are not expected to be able to work in all
environments (and shells). While powerful, because of this limitation, we didn't
want to architect the entire experience around something that wouldn't always
work.
## Resources
[comment]: # Be sure to add links to references, resources, footnotes, etc.
### Examples
[This thread on the Terminal repo](https://github.com/microsoft/terminal/issues/14680), where the user included a long collection of commands to run
### Footnotes
<a name="footnote-1"><a>[1]:
[Jupyter notebooks]: https://jupyter.org/
[a Jupyter example]: https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb
[this comment on HackerNews]: https://news.ycombinator.com/item?id=26617656
[Marks]: https://github.com/microsoft/terminal/issues/11000

View File

@@ -0,0 +1,226 @@
---
author: Mike Griese
created on: 2022-02-16
last updated: 2023-07-07
issue id: TODO!
---
# Shell Completions Protocol
## Abstract
> Note:
>
> This is a draft document - mainly just notes from early iterations on the
> [Suggestions UI]. The protocol laid out in this version of the doc is very
> much not finalized.
>
> It is included with the remainder of my North Star docs, because it was always
> a part of that story. As we iterate on this protocol, we'll revise this doc
> with the final protocol.
## Background
### Inspiration
### User Stories
### Elevator Pitch
### Business Justification
## Solution Design
### Escape sequence
```
OSC 633 ; Completions ; Ri ; Rl ; Ci ; Js ST
```
where
* `Ri`: the replacement index (TODO!?)
* `Rl`: the replacement length (TODO!?)
* `Rl`: the current cursor position in the command (TODO!?)
* `Js`: A json-encoded blob describing the suggested completions. See [Completion Schema](#completion-schema) for a more thorough description
### Completion Schema
#### Example JSON blobs
* Typed text: ```Get-M```
```jsonc
[
{
"CompletionText": "Get-MarkdownOption",
"ListItemText": "Get-MarkdownOption",
"ResultType": 2,
"ToolTip": "Get-MarkdownOption\r\n"
},
{
"CompletionText": "Get-Member",
"ListItemText": "Get-Member",
"ResultType": 2,
"ToolTip": "Get-Member\r\n"
},
{
"CompletionText": "Get-Module",
"ListItemText": "Get-Module",
"ResultType": 2,
"ToolTip": "\r\nGet-Module [[-Name] <string[]>] [-FullyQualifiedName <ModuleSpecification[]>] [-All] [<CommonParameters>]\r\n\r\nGet-Module [[-Name] ... (omitted for brevity)"
},
// ...
]
```
* Typed text: ```Get-Module ```
```json
[
{
"CompletionText": "Microsoft.PowerShell.Management",
"ListItemText": "Microsoft.PowerShell.Management",
"ResultType": 8,
"ToolTip": "Description: \r\nModuleType: Manifest\r\nPath: C:\\program files\\powershell\\7\\Modules\\Microsoft.PowerShell.Management\\Microsoft.PowerShell.Management.psd1"
},
{
"CompletionText": "Microsoft.PowerShell.Utility",
"ListItemText": "Microsoft.PowerShell.Utility",
"ResultType": 8,
"ToolTip": "Description: \r\nModuleType: Manifest\r\nPath: C:\\program files\\powershell\\7\\Modules\\Microsoft.PowerShell.Utility\\Microsoft.PowerShell.Utility.psd1"
},
{
"CompletionText": "PSReadLine",
"ListItemText": "PSReadLine",
"ResultType": 8,
"ToolTip": "Description: Great command line editing in the PowerShell console host\r\nModuleType: Script\r\nPath: C:\\program files\\powershell\\7\\Modules\\PSReadLine\\PSReadLine.psm1"
}
]
```
### PowerShell function
```ps1
function Send-Completions {
$commandLine = ""
$cursorIndex = 0
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$commandLine, [ref]$cursorIndex)
$completionPrefix = $commandLine
# Get completions
$result = "`e]633;Completions"
if ($completionPrefix.Length -gt 0) {
# Get and send completions
$completions = TabExpansion2 -inputScript $completionPrefix -cursorColumn $cursorIndex
if ($null -ne $completions.CompletionMatches) {
$result += ";$($completions.ReplacementIndex);$($completions.ReplacementLength);$($cursorIndex);"
$result += $completions.CompletionMatches | ConvertTo-Json -Compress
}
}
$result += "`a"
Write-Host -NoNewLine $result
}
```
## UX / UI Design
![A prototype from early 2023](img/3121-sxn-menu-2023-000.gif)
### Description tooltips
### Segoe Fluent Icons
See: https://github.com/PowerShell/PowerShellEditorServices/pull/1738
| Name | val | Icon ideas | description
| ------------------- | --- | --------------------- | --------------
| Text | 0 | | An unknown result type, kept as text only.
| History | 1 |e81c History | A history result type like the items out of get-history.
| Command | 2 |ecaa AppIconDefault | A command result type like the items out of get-command.
| ProviderItem | 3 |e8e4 AlignLeft | A provider item.
| ProviderContainer | 4 |e838 FolderOpen | A provider container.
| Property | 5 |e7c1 Flag | A property result type like the property items out of get-member.
| Method | 6 |ecaa AppIconDefault | A method result type like the method items out of get-member.
| ParameterName | 7 |e7c1 Flag | A parameter name result type like the Parameters property out of get-command items.
| ParameterValue | 8 |f000 KnowledgeArticle| A parameter value result type.
| Variable | 9 | | A variable result type like the items out of get-childitem variable.
| Namespace | 10 |e943 Code | A namespace.
| Type | 11 | | A type name.
| Keyword | 12 | | A keyword.
| DynamicKeyword | 13 |e945 LightningBolt | A dynamic keyword.
#### Sample XAML
The following XAML produces a menu that looks like the following:
![](img/shell-completion-tooltip-000.png)
I included a scrollviewer, because I couldn't seem to find a way to get the tooltip to be wider. I'm sure there's better ways of styling it in real code (vs just in XAML studio).
```xml
<muxc:TeachingTip x:Name="MyTooltip"
IsOpen="True"
MinWidth="900"
Title="Get-Module">
<ScrollViewer HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Hidden" >
<TextBlock>
<Run>Get-Module [[-Name] &lt;string[]&gt;] [-FullyQualifiedName &lt;ModuleSpecification[]&gt;] [-All] [&lt;CommonParameters&gt;]
</Run>
<LineBreak/>
<Run>Get-Module [[-Name] &lt;string[]&gt;] -ListAvailable [-FullyQualifiedName &lt;ModuleSpecification[]&gt;] [-All] [-PSEdition &lt;string&gt;] [-SkipEditionCheck] [-Refresh] [&lt;CommonParameters&gt;]
</Run>
<LineBreak/>
<Run>Get-Module [[-Name] &lt;string[]&gt;] -PSSession &lt;PSSession&gt; [-FullyQualifiedName &lt;ModuleSpecification[]&gt;] [-ListAvailable] [-PSEdition &lt;string&gt;] [-SkipEditionCheck] [-Refresh] [&lt;CommonParameters&gt;]
</Run>
<LineBreak/>
<Run>Get-Module [[-Name] &lt;string[]&gt;] -CimSession &lt;CimSession&gt; [-FullyQualifiedName &lt;ModuleSpecification[]&gt;] [-ListAvailable] [-SkipEditionCheck] [-Refresh] [-CimResourceUri &lt;uri&gt;] [-CimNamespace &lt;string&gt;] [&lt;CommonParameters&gt;]
</Run>
</TextBlock>
</ScrollViewer>
</muxc:TeachingTip>
```
## Tenents
<table>
<tr><td><strong>Compatibility</strong></td><td>
[TODO!]: TODO! -----------------------------------------------------------------
</td></tr>
<tr><td><strong>Accessibility</strong></td><td>
The SXN UI was designed with the goal of making commandline shell suggestions _more_ accessible. As Carlos previously wrote:
> Screen readers struggle with this because the entire menu is redrawn every time, making it harder to understand what exactly is "selected" (as the concept of selection in this instance is a shell-side concept represented by visual manipulation).
>
> ...
>
> _\[Shell driven suggestions\]_ can then be leveraged by Windows Terminal to create UI elements. Doing so leverages WinUI's accessible design.
This will allow the Terminal to provide more context-relevant information to
screen readers.
</td></tr>
<tr><td><strong>Sustainability</strong></td><td>
No sustainability changes expected.
</td></tr>
<tr><td><strong>Localization</strong></td><td>
[TODO!]: TODO! -----------------------------------------------------------------
The localization needs of the Suggestions UI will be effectively the same as the
needs of the Command Palette.
</td></tr>
</table>
[Suggestions UI]: ./Suggestions-UI.md

View File

@@ -0,0 +1,19 @@
---
author: Mike Griese
created on: 2022-03-28
last updated: 2023-07-07
issue id: 11000, 1527, 6232
---
##### [Original issue: [#1527]] [experimental PR [#12948]] [remaining marks [#14341]]
# Windows Terminal - Shell Integration (Marks)
> Note:
>
> This document has been moved. It was originally authored as a part of the
> North Star docs, but later submitted for its own review. You can find it in PR
> at
> [microsoft/terminal#14792](https://github.com/microsoft/terminal/pull/14792),
> or the final home of this doc in
> [Shell-Integration-Marks.md](../%2311000%20-%20Marks/Shell-Integration-Marks.md)

View File

@@ -0,0 +1,670 @@
---
author: Mike Griese
created on: 2022-08-22
last updated: 2023-02-16
issue id: 1595
---
# Windows Terminal - Suggestions UI
## Abstract
Multiple related scenarios have come up where it would be beneficial to display
actionable UI to the user within the context of the active terminal itself. This
UI would be akin to the Intellisense UI in Visual Studio. It appears right where
the user is typing, and can help provide immediate content for the user, based
on some context. The "Suggestions UI" is this new ephemeral UI within the
Windows Terminal that can display different types of actions, from different
sources.
## Background
The Suggestions UI is the singular UI by which the Terminal can display a
variety of suggestions to the user. These include:
* Recent commands the user has executed in this terminal, powered by shell integration.
* Recent directories, similarly powered by shell integration
* Completions from the shell itself (like the shell completions in PowerShell)
* Tasks, which are `sendInput` actions from the user's settings
* Buffer Completions, which is a dumb type of autocomplete based on words in the buffer
* and more (as provided via extensions)
All of these scenarios are places where it makes sense to present the user a
menu at the point of text insertion in the terminal control itself.
### Inspiration
Primarily, the inspiration is any Intellisense-like experience, in any app.
Visual Studio, VsCode, PowerShell, vim, Sublime any JetBrains IDE - there's more
than enough examples in the wild.
Ultimately, the inspiration for the Suggestions UI came from a bunch of places
all at once. In the course of a few months though, it became clear that we'd
need a unified UI for displaying a variety of suggestion-like experiences in the
Terminal. Our work with the PowerShell and VsCode teams helped refine these
requests all into the unified design below.
### User Stories
Story | Size | Description
--|-----------|--
| 🐣 Crawl | The user can bring up the Suggestions UI with recent commands, powered by shell integration
| 🐣 Crawl | [#12863] The user can bring up the Suggestions UI with recent directories, powered by shell integration
| 🚶 Walk | The user can bring up the Suggestions UI with tasks from their settings
| 🚶 Walk | CLI apps can invoke the Suggestions UI with a new VT sequence
| 🚶 Walk | The Suggestions UI can be opened using the current typed commandline as a filter
| 🚶 Walk | Recent commands and directories are stored in `state.json`, across sessions
| 🏃‍♂️ Run | Suggestions can have descriptions presented in / alongside the UI
| 🏃‍♂️ Run | The Suggestions UI can be opened without any nesting
| 🏃‍♂️ Run | The Suggestions UI can be opened, nested by `source` of the suggestion
| 🚀 Sprint | Extensions can provide suggestion sources for the Suggestions UI
| 🚀 Sprint | The Suggestions UI can be opened in "inline" mode, only showing the text of the first suggestion
### Elevator Pitch
The Suggestions UI is a UI element displayed in the Terminal for providing
different types of text suggestions to the user - anything from recently run
commands, to saved commands, to tab-completion suggestions from the shell
itself.
## Business Justification
It will delight developers.
Furthermore, our partners on the Visual Studio team have been requesting similar
functionality for some time now. The way autocompletion menus in PowerShell
currently interact with UIA clients leaves much to be desired. They'd like a way
to provide richer context to screen readers. Something to enable the terminal to
more specifically describe the context of what's being presented to the user.
## Scenario Details
### UI/UX Design
#### Prototypes
The following gif was a VsCode prototype of [shell-driven autocompletion]. This
is the point of reference we're starting from when talking about what the
suggestions UI might look like.
![](img/vscode-shell-suggestions.gif)
These suggestions are populated by logic within PowerShell itself, and
communicated to the Terminal. The Terminal can then display them in the
Suggestions UI.
The following gifs demonstrate a prototype of what that might look like for the
Terminal. These are meant to be informative, not normative, representations of
what the UI would look like.
![](img/shell-autocomplete-jul-2022-000.gif)
An prototype of the recent commands UI, powered by shell integration:
![](img/command-history-suggestions.gif)
An prototype of the tasks UI, powered by the user's settings:
![](img/tasks-suggestions.gif)
(admittedly, the `TeachingTip` needs better placement).
In general, the Suggestions UI will present a list of elements to select from,
near the text cursor. This control might be contain a text box for filtering
these items (a "**palette**"), or it might not (a "**menu**").
![An example of the menu mode](img/3121-sxn-menu-2023-000.gif)
#### Palette vs Menu
Depending on how the suggestions UI is invoked, we may or may not want to
display a text box for filtering these suggestions. Consider the Intellisense
menu in Visual Studio. That's a UI that only allows for up/down for navigation
(and enter/tab for selecting the suggestion).
For suggestions driven by the Terminal, we'll display a filtering text box in
the Suggestions UI. This is similar to the command palette's search - a fuzzy
search to filter the contents. This is the "**palette**" style of the
suggestions dialog.
For completions driven by the shell, we should probably not display the
filtering text box. This is the "**menu**" style of the suggestion dialog. The
user is primarily interacting with the shell here, not the Terminal.
> **Warning**
> TODO! For discussion, possibly with a real UX designer.
How should we handle completions here? Tab? Enter? Right-Arrow? Should we have
an element selected when we open the menu, or should tab/enter only work once
the user has used the arrows at least once? Sublime allows for <kbd>tab</kbd> to
complete the suggestion immediately.
Consider also that these suggestions might be provided by the shell, as the user
is typing at a commandline shell. For something like PowerShell, the user might
want to start typing a command and have it tab-complete based off the shell's
tab expansion rules. PowerShell's inline suggestions use right-arrow to
differentiate "use this suggestion" vs tab for "tab expand what I'm typing at
the prompt". We should probably preserve this behavior.
We probably don't want to provide different experiences for the **menu** version
won't be pressing tab to tab-complete at the shell (the focus is out of the of
the Suggestions UI vs. the **palette** version. In the palette version, the user
terminal and into the Suggestions UI).
We will want to make sure that there's some semblance of consistency across our
implementation for the Suggestions UI, our own Command Palette, VsCode's
intellisense and their own implementation of shell-completions in the Terminal.
> **Note**
> In my prototype, for the "Menu" mode, I accepted ALL of right-arrow, tab, and
> enter as "accept completion", and any other key dismissed the UI. This _felt_
> right for that mode. I'm not sure we could make the same call for "palette"
> mode, where we'd need tab for navigating focus.
### Implementation Details
#### Fork the Command Palette
We're largely going to start with the Command Palette to build the Suggestions
UI. The Command Palette is already a control we've built for displaying a
transient list of commands and dispatching them to the rest of the app.
Currently, the Command Palette is a single static control, at the top-center of
the Terminal window, and occupying a decent portion of the screen. For the
Suggestions UI, we'll instead want to make sure that the control appears
relative to the current cursor position.
We'll start by taking the command palette, and copying it over to a new control.
This will allow us to remove large chunks of code dealing with diffent modes
(i.e. the tab switcher), and code dealing with prefix characters to switch
modes.
We'll need to make some small modifications to enable the Suggestions UI to
* work as a text cursor-relative control
* exist as a Flyout outside the bounds of the Terminal window
* If the Suggestions UI is too close to the bottom of the screen, we'll need it to open
"upwards", with the search box at the _bottom_ and the list extending above it
* prevent it from switching to command-line mode
* display tooltips / `TeachingTip`s / some secondary flyout with a description
of the suggestion (if provided)
#### Completion sources
The Suggestions UI will support suggestions from a variety of different
"sources". As an example, consider the following actions:
```json
{ "command": { "action":"suggestions", "source": "commandHistory" } },
{ "command": { "action":"suggestions", "source": "directoryHistory" } },
{ "command": { "action":"suggestions", "source": "tasks" } },
{ "command": { "action":"suggestions", "source": "local" } },
{ "command": { "action":"suggestions", "source": ["local", "tasks", "commandHistory"] } },
{ "command": { "action":"suggestions", "source": "Microsoft.Terminal.Extensions.BufferComplete" } },
```
Each of these `suggestions` actions would open the Suggestions UI with a
different set of actions.
* `commandHistory`: Use commands from this session, as identified via shell
integration. This won't be able to return any suggestions if the user has not
configured their shell to support shell integration sequences yet.
* `directoryHistory`: Populate the list with a series of `cd {path}` commands,
where the paths are populated via shell integration. Paths are in MRU order.
* `tasks`: Populate the list with all `sendInput` actions in the user's settings
file. The command structure should remain unchanged. For example, if they have
`sendInput` actions nested under a "git" command, then the "git" entry will
remain in this tasks view with their `sendInput` actions nested inside it. For
more details, see the [Tasks] spec.
* `local`: Populate the list with tasks that are located in the CWD, in a file
named `.wt.json`. For more details, see the [Tasks] spec.
* `Microsoft.Terminal.Extensions.BufferComplete`: As an example, this
demonstrates how an action might be authored to reference a suggestion source
from an extension.
Each of these different sources will build a different set of `Command`s,
primarily populated with `sendInput` actions. We'll load those `Command`s into
the Suggestions UI control, and open it at the text cursor.
To drill in on a single example - the `commmandHistory` source. In that
particular case, the TerminalPage will query the active TermControl for a list
of it's recent commands. If it knows these (via shell integration), then the
TerminalPage will use that list of commands to build a list of `sendInput`
actions. Those will then get fed to the suggestions UI.
Not listed above is [shell-driven autocompletion]. These aren't something that
the Terminal can invoke all on it's own - these are something the shell would
need to invoke themselves.
#### Pre-populate the current commandline context
Consider the following scenario. A user has typed `git c` in their shell, and
has [shell integration] enabled for their shell. They want to open the
Suggestions UI filtered to their recent history, but starting with what they've
already typed. To support this scenario, we'll add an addional property:
* `"useCommandline"`: `bool`
* `true`: the current commandline the user has typed will pre-populate the
filter of the Suggestions UI. This requires that the user has enabled shell
integration in their shell's config.
* `false`: the filter will start empty.
With that setting, the user can achieve their desired UX with the following action:
```json
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true } },
```
Now, when they type `git c` and invoke the Suggestions UI, they can immediately
start searching for recent commands that started with `git c`.
#### Default actions
I propose adding the following actions to the Terminal by default:
```json
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true } },
{ "command": { "action":"suggestions", "source": "directoryHistory" } },
{ "command": { "action":"suggestions", "source": ["local", "tasks", "commandHistory"], "useCommandline": true, "nesting": "disabled" } },
{ "command": { "action":"suggestions", "source": ["all"], "useCommandline": false, "nesting": "source" } },
```
These actions are colloquially:
* Give me suggestions from my recent commands, using what I've typed
* Give me suggestions of directories I've recently been in
* _(After [Tasks] are implemented)_ Give me suggestions from recent commands,
commands I've saved, and commands for this project. Don't nest any, so they're
all in the top-level menu. Use what I've typed already to start filtering.
* Just open the Suggestions UI with all suggestions sources, and group them by
the source of the suggestions.
This should cover most of the basic use cases for suggestions.
## Tenents
<table>
<tr><td><strong>Compatibility</strong></td><td>
This shouldn't break any existing flows. This is a general purpose UI element,
to be extended in a variety of ways. Those customizations will all be opt-in by
the user, so I'm not expecting any breaking compatibility changes here.
</td></tr>
<tr><td><strong>Accessibility</strong></td><td>
The Suggestions UI was designed with the goal of making commandline shell
suggestions _more_ accessible. As Carlos previously wrote:
> Screen readers struggle with this because the entire menu is redrawn every time, making it harder to understand what exactly is "selected" (as the concept of selection in this instance is a shell-side concept represented by visual manipulation).
>
> ...
>
> _\[Shell driven suggestions\]_ can then be leveraged by Windows Terminal to create UI elements. Doing so leverages WinUI's accessible design.
This will allow the Terminal to provide more context-relevant information to
screen readers.
</td></tr>
<tr><td><strong>Sustainability</strong></td><td>
No sustainability changes expected.
</td></tr>
<tr><td><strong>Localization</strong></td><td>
The localization needs of the Suggestions UI will be effectively the same as the
needs of the Command Palette.
</td></tr>
</table>
## Implementation Plan
### 🐣 Crawl
* [ ] Fork the Command palette to a new UI element, the `SuggestionsControl`
* [ ] Enable previewing `sendInput` actions in the Command Palette and `SuggestionsControl`
* [ ] Enable the `SuggestionsControl` to open top-down (aligned to the bottom of the cursor row) or bottom-up (aligned to the top of the cursor row).
* [ ] Disable sorting on the `SuggestionsControl` - elements should presumably be pre-sorted by the source.
* [ ] Expose the recent commands as a accessor on `TermControl`
* [ ] Add a `suggestions` action which accepts a single option `recentCommands`. These should be fed in MRU order to the `SuggestionsControl`.
* [ ] Expose the recent directories as a accessor on `TermControl`, and add a `recentDirectories` source.
### 🚶 Walk
* [ ] Add a `tasks` source to `suggestions` which opens the Suggestions UI with
a tree of all `sendInput` commands
* [ ] Enable the `SuggestionsControl` to open with or without a search box
* [ ] Plumb support for shell-driven completions through the core up to the app
* [ ] Figure out how exactly we want to persist recent commands / directories. Globally? Per-profile? Layered? Per executable (does that even make sense)?
* [ ] Persist recent commands / directories accordingly
* [ ] Expose the _current_ commandline from the `TermControl`
* [ ] Add a `useCommandline` property to `suggestions`, to pre-populate the search with the current commandline.
### 🏃‍♂️ Run
* [ ] Add a `description` field to `Command`
* [ ] Add a `TeachingTip` (or similar) to the Suggestions UI to display
descriptions (when available)
* [ ] Use the `ToolTip` property of shell-driven suggestions as the description
* [ ] Add a boolean `nesting` property which can be used to disable nesting on the `tasks` source.
* [ ] Add the ability for `nesting` to accept `enabled`/`disabled` as `true`/`false` equivalents
* [ ] Add the ability for `nesting` to accept `source`, which instead groups all
commands to the Suggestions UI by the source of that suggestion.
### 🚀 Sprint
The two "sprint" tasks here are much more aspirational than the other listed
scenarios, so breaking them down to atomic tasks sees less reasonable. We'd have
to spend a considerable amount more time figuring out _how_ to do each of these
first.
For example - extensions. We have yet to fully realize what extensions _are_.
Determining how extensions will provide suggestions is left as something we'll
need to do as a part of the Extensions spec.
## Conclusion
Here's a sample json schema for the settings discussed here.
```json
"OpenSuggestionsAction": {
"description": "Arguments corresponding to a Open Suggestions Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "suggestions"
},
"source": {
"$ref": "#/$defs/SuggestionSource",
"description": "Which suggestion sources to filter."
},
"useCommandline": {
"default": false,
"description": "When set to `true`, the current commandline the user has typed will pre-populate the filter of the Suggestions UI. This requires that the user has enabled shell integration in their shell's config. When set to false, the filter will start empty."
},
"nesting": {
"default": true,
"description": "When set to `true`, suggestions will follow the provided nesting structure. For Tasks, these will follow the structure of the Command Palette. When set to `false`, no nesting will be used (and all suggestions will be in the top-level menu.",
"$comment": "This setting is a possible follow-up setting, not required for v1. "
}
}
}
]
},
"SuggestionSource": {
"default": "all",
"description": "Either a single suggestion source, or an array of sources to concatenate. Built-in sources include `commandHistory`, `directoryHistory`, `tasks`, and `local`. Extensions may provide additional values. The special value `all` indicates all suggestion sources should be included",
"$comment": "`tasks` and `local` are sources that would be added by the Tasks feature, as a follow-up"
"oneOf": [
{
"type": [ "string", "null" ]
},
{
"type": "array",
"items": { "type": "string" }
}
]
},
```
### Future Considerations
* Another extension idea: `WithFig.FigCompletions`. Imagine an extension that
could parse existing [Fig] completion specs, and provide those as suggestions
in this way.
* This might be a good example of an async suggestion source. The current
commandline is used as the starting filter, and the suggestions would be
populated by some `fig` process / thread / async operation that returns the
suggestions.
* If the user hasn't enabled shell completion, we could add text to the
`commandHistory` or `directoryHistory` menus to inform the user how they could
go enable shell integration.
* Maybe there could be a per-profile setting for automatic suggestions after
some timeout. Like, as you type, a menu version of the Suggestions UI appears.
So you could just start typing `git c`, and it would automatically give you a
menu with suggestions, implicitly using the typed command as the "filter".
* Maybe we could do this as an `implicit` property on the `suggestions` action
* It might make sense in the future to have the Suggestions UI exposed as an
element of the `TermControl` itself, rather than an element of the
`TerminalPage`. Especially when we consider [shell-driven autocompletion].
That seems like a scenario that the `TermControl` should expose for all
consumers of the control, without them manually needing to write their own UI
element to manage it. This probably could be done without many changes
* Instead of operating on `Command`s and actions from the terminal settings,
the control could just know that all the entries in the menu are "send
input" "actions".
* The control could offer a method to manually invoke the Suggestions UI for a
list of {suggestion, name, description} objects.
* The app layer could easily translate between sendInput actions and these
pseudo-actions.
#### Description Tooltips
> **Note**: _This is left as a future consideration for the initial draft of
> this spec. I'd like to flesh out [shell-driven autocompletion] more before
> committing any plans here.
It would be beneficial for the Suggestions UI to display additional context to
the user. Consider a extension that provides some commands for the user, like a
hypothetical "Docker" extension. The extension author might be able to give the
commands simplified names, but also want to expoose a more detailed description
of the commands to the user.
Or consider the Suggestions UI when invoked by [shell-driven autocompletion].
The shell might want to provide help text to the user with each of the
suggestions. This would allow a user to browse through the suggestions that they
might not know about, and learn how they work before committing to one.
Only the help text for the currently hovered command should be presented to the
user. To support this kind of UX, we'll add an optional flyout of some sort to
display with the Suggestions UI. This flyout will only appear if there's more
information provided to the Terminal.
This might be in the form of a `TeachingTip`, as in this example:
![](img/tasks-suggestions.gif)
Actions in the settings could also accept an optional `description` property, to
specify the string that would be presented in that flyout.
#### Pre-filtering the UI & filter by source
> **Note**: _This is a brainstorm I considered while writing this spec. I would
> not not include it in the v1 of this spec. Rather, I'd like to leave it for
> where we might go with this UX in the future._
Do want to support different _types_ of nesting? So instead of just the default,
there could be something like `nesting: "source"`, to create a mune structured
like:
```
Suggestions UI
├─ Recent Commands...
│ ├─ git checkout main
│ ├─ git fetch
│ └─ git pull
├─ Recent Directories...
│ ├─ d:\dev
│ ├─ d:\dev\public
│ └─ d:\dev\public\terminal
├─ Saved tasks...
│ ├─ Git...
│ │ └─ git commit -m "
│ │ └─ git log...
│ └─ bx & runut
└─ Docker
├─ docker build --platform linux/amd64 <path>
└─ docker logs -f --tail <lines_count> <container_name>
```
> **Note**
> I'm using `Docker` as an example fragment extension that provides
> some `docker` commands. When grouping by `"source"`, we could pull those into
> a seperate top-level entry. When not grouping by `"source"`, those would still
> show up with the rest of `tasks`. )
#### Store recent commands across sessions
> **Note**
> _I'm not sure we really want to put this in this spec or not, hence
> why it's in the "Future considerations" section. I think it's worth
> mentioning. This might be better served in the [shell integration] doc._
We'll probably want a way for recent commands to be saved across sessions. That way, your `cmd.exe` command history could persist across sessions. We'd need:
* A setting to enable this behavior
* A setting to control the context of these saved commandlines.
* Do we want them saved per-profile, or globally?
* If they're saved per-profile, maybe a profile can opt-in to loading all the commands?
* How does defterm play with this? Do we "layer: by concatenating per-profile commands with `profiles.defaults` ones?
* A button in the Settings UI for clearing these commands
* Should fragments be able to pre-populate "recent commands"?
* I'm just gonna say _no_. That would be a better idea for Tasks (aka just a `sendInput` Action that we load from the fragment normally as a Task), or a specific suggestion source for the fragment extension.
#### Inline mode
> **Note**
> _This is a half-baked idea with some potential. However, I don't
> think it needs to be a part of the v1 of the Suggestions UI, so I'm leaving it
> under future considerations for a future revision._
Do we want to have a suggestions UI "mode", that's just **one** inline
suggestion, "no" UI? Some UX ala the `PsReadline` recent command suggestion
feature. Imagine, we just display the IME ghost text thing for the first result,
given the current prompt?
Take the following action as an example:
```json
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true, "inline": true } },
```
Type the start of some command at the prompt, and press that key. Presto, we do
the `pwsh` thing. Ghost text appears for the first match in the `commandHistory`
for what the user has typed. If they press another key, ~they've typed into the
"hidden" Suggestions UI, which filters the (hidden) list more, and updates the
one inline suggestion.~
Or, instead, typed keys go to the shell, and then we re-query the commandline,
and update the filter accordingly. That would allow tab-completion to still
work. We'd use <kbd>right arrow</kbd> to accept the suggestion (and dismiss the
ghost text preview).
This would seemingly SUPER conflict with PowerShell's own handler. Probably not
something someone should enable for PowerShell 7 profiles if they're using that
feature.
### Rejected ideas
These are musings from earlier verisons of the spec.
* **Asynchronous prompting**: This was rejected because it was so fundamentally
different from the rest of the UX of the Suggestions UI, it didn't make sense
to try and also do that behavior.
Furthermore, async sources wouldn't work with sync
ones, at all. E.g. if you did `source: ["tasks", "myAsyncSource"]`. It doesn't
make sense to start with a list of `tasks`, then type, find no tasks, but then
oh! the UI fills in some other suggestions too. That's weird.
* ...
#### REJECTED: Asynchronous prompting
Certain suggestion sources might want to provide results asynchronously.
Consider a source that might want to make a web request to populate what strings
to suggest. That source might want to prompt the user for input first, then
dispatch the request, then populate the UI. Or something like a `fig`-like
suggestion source, which would need to parse some files from the disk to
generate the list of suggestions.
The easiest way to do this would be to provide a secondary UI element for
prompting the user for input, doing the request in the background, then opening
the UI later. However, that feels a little disjointed. Could we instead provide
a more continuous experience?
The following is a proposal for using the Suggestions UI itself as the control
to prompt the user for input.
```c++
TerminalPage::SetUpSuggestionsUI()
{
const auto& asyncSource{ AsyncSuggestions() };
suggestionsUI.OnInputChanged({ asyncSource, AsyncSuggestions::InputChangedHandler});
// In this example, we don't want the UI to filter item based on the input
// string - the source has already determined the list of relevant matches.
suggestionsUI.FilterByInput(false);
asyncSource.SuggestionsChanged([](const auto& newCommands){
suggestionsUI.Loading(false);
suggestionsUI.Commands(newCommands);
})
}
void AsyncSuggestions::InputChangedHandler(FilterChangedArgs args)
{
// kick off a trailing ThrottledFunc to do a new query
_loadNewResults->Run(args.NewInputText());
// If we get another request, we might want to cancel the pending throttled
// func entirely, and start the timeout fresh. Just so that we only make a
// query for the final string they type.
args.RequestLoading(true); // pass a boolean back up in the args, so that
// the Suggestions UI can clear out the current commands, and start displaying an
// indeterminate progress wheel.
}
```
That would basically _have_ to be special cased for this source, at least for
now. We could refactor that later to beetter deal with extensions.
Let's make sure this would work for something `fig`-like, where the "prompt" is
literally the prompt, what the user has already typed at the commandline.
After some discussion:
* How do we differentiate the prompting version of the Suggestions UI from the
filtering version?
* The prompting version _doesn't_ filter results
* Async modes wouldn't work with sync ones
## Resources
[comment]: # Be sure to add links to references, resources, footnotes, etc.
Prominent North Star references:
* [Tasks]
* [shell integration]
* [shell-driven autocompletion]
### Footnotes
<a name="footnote-1"><a>[1]:
[Fig]: https://github.com/withfig/autocomplete
[Warp]: https://www.warp.dev/
[workflows]: https://docs.warp.dev/features/workflows
[also working on workflows]: https://fig.io/user-manual/workflows
[winget script]: https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
[#1595]: https://github.com/microsoft/terminal/issues/1595
[#7039]: https://github.com/microsoft/terminal/issues/7039
[#3121]: https://github.com/microsoft/terminal/issues/3121
[#10436]: https://github.com/microsoft/terminal/issues/10436
[#12927]: https://github.com/microsoft/terminal/issues/12927
[#12863]: https://github.com/microsoft/terminal/issues/12863
[#5790]: https://github.com/microsoft/terminal/issues/5790
[Terminal North Star]: ./Terminal-North-Star.md
[#keep]: https://github.com/zadjii/keep
[VsCode Tasks]: https://github.com/microsoft/terminal/blob/main/.vscode/tasks.json
[Tasks]: ./Tasks.md
[shell integration]: ./Shell-Integration-Marks.md
<!-- TODO! -->
[shell-driven autocompletion]: ./Terminal-North-Star.md#Shell_autocompletion

View File

@@ -0,0 +1,511 @@
---
author: Mike Griese
created on: 2022-08-22
last updated: 2022-12-14
issue id: 1595
---
# Windows Terminal - Tasks
> **Note**:
>
> This is a draft document. This doc largely predates the creation of the
> [Suggestions UI]. Many of the elements of this doc need to be updated to
> reflect newer revisions to the Suggestions UI.
>
> It is included with the remainder of my North Star docs, because it was always
> a part of that story. A future revision will come through to polish this doc
> into a final form.
## Abstract
The command line is a highly powerful tool. However, its power is dependent on
the user's knowledge of the specific commands, flags and parameters needed to
perform tasks from the command-line. For simple everyday commands, this might not
be so hard. For longer commands, or ones used less frequently, there's quite a
bit of mental overhead trying to recall the exact syntax. For teams, it might be
helpful to share these tasks with everyone on the project. The Terminal can be a
aveneue by which complicated tasks can be remembered, shared, discovered and
recalled by the user simply thinking **"what do I want to do"**, rather than
"how do I do it".
## Background
> **Note**:
>
> This largely builds off of work in the [Suggestions UI], for displaying these
> tasks to the user. Make sure to read that spec first.
### Inspiration
The primordial version of this idea was probably [#keep] - a command-line tool I
wrote for stashing long command-lines and directories, and recalling them with
just a number. We've had many variations on this idea over the years - [#1595]
was probably the first such request on the Terminal repo. ITerm2 also had [a
similar feature](https://iterm2.com/images/CommandHistory.png). Theirs was more
directly tied to shell integration (that menu is populated from commands that
they know were run in the shell). In the absence of shell integration though, it
should be able to save these commands to a menu manually.
It is hard to say that the ultimate vision here isn't partially inspired by the
"[workflows]" of [Warp], or by [Fig]. These are modern tools that seek to
augment the command-line experience, by making the command-line more
approachable. Warp quite clearly has the same concept in "workflows" - scripts
which the user can build and Warp (a Terminal emulator) can insert quickly. Fig,
on the other hand, is more focused on just simplifing the command-line
experience. Fig is more about providing additional metadata to the user as
they're typing. They are [also working on workflows], so there's clearly quite a
bit of ecosystem-wide demand for more discoverable command-line tooling.
Consider also [VsCode Tasks]. These are files which can be placed in the root of
a workspace, and share common tasks between users of that workspace. They've got
support for starting processes, with a set of args. These args can also be
picked at runtime, and custom sets of arguments can be specified for individual
arguments.
We've had verbatim feedback that developers already attempt to record useful
commandlines in various different ways - in OneNotes, in shell scripts, in
aliases. Sharing these Providing a unified way to easily store, browse, and use
these command lines should be valuable to developers already doing this.
Furthermore, developers often share these commands with the rest of their teams.
A static file in their project containing commands for the whole team seems like
a simple solution to this problem.
### User Stories
Story | Size | Description
--|-----------|--
A | 🐣 Crawl | Users can bring up a menu of command line tasks and quickly execute them
B | 🐣 Crawl | Fragment apps can provide tasks to a users settings
D | 🚶 Walk | The user can save commands straight to their settings with a `wt` command
E | 🚶 Walk | Users can have different tasks enabled for different profiles(/shells?)
F | 🏃‍♂️ Run | The terminal can automatically look for command fragments in the tree of the CWD
H | 🏃‍♂️ Run | Tasks are filterable by tool (`git`, `docker`, etc.)
I | 🏃‍♂️ Run | ? Tasks can both be atomic _tasks_ and longer scripts. Tasks can be sent straightaway to the Terminal, while the longer scripts are more for reference (ex: [winget script]).
J | 🏃‍♂️ Run | Tasks can be filtered by text the user has already typed
K | 🚀 Sprint | Tasks can have promptable sections of input
L | 🚀 Sprint | Community tasks are hosted in a public GH repo
M | 🚀 Sprint | A simple UX (either web or in Terminal) is exposed for interacting with public GH repo of tasks
### Elevator Pitch
The Terminal can remember long command-lines and display them with user-friendly
descriptions of _what they actually do_. These tasks can be searched by intent,
rather than the particular combination of flags. They can be shared with members
of your team, so everyone has easy access to common tasks for a project.
### Why not just aliases / native script files?
Why not just take these tasks and put them into a shell alias? For longer tasks,
why not just stick them in a `.ps1`/`.bat`/`.sh`/etc file? This is an option
that's existed since the time immemorial. However, this still requires the user
to remember that they've created these aliases/scripts, remember where they're
stored, and remember how they work.
By providing a dedicated UI for these command-lines, they can always be at your
fingertips. No need to remember what the alias for a particular command-line is -
just look up what you want to do. Aliases and scripts are no longer scattered
across `.bashrc`, `.bash_profile`, `.profile`, etc, they can all be stashed in
the Terminal config, or in the project they're relevant to. By stashing them
alongside the code, then anyone else coming to work on the code can have
immediate access to useful sets of tasks.
Aliases have a tendency towards more experienced shell users. This proposal
instead brings the power of these aliases and scripts right to the foreground,
with a cross-shell mechanism of exposing them to even beginners. With fragment
extensions, tools can bundle common workflows together with their application so
the Terminal can automatically load them for the user.
### Community Tasks
_The big stretch version of this feature._
A community currated list of Tasks, for various tools. Stored publicly on a
GitHub repo (a la the winget-pkgs repo). Users can submit tasks with
descriptions of what the task does. The Terminal can plug into that repo
automatically and fetch the latest community commands, immediately giving the
user access to a wide bearth of common tasks.
## Business Justification
It will delight developers.
## Scenario Details
### UI/UX Design
For the most part, we'll be using the [Suggestions UI] to display tasks to the
user. This is a text cursor-relative UI surface that can quickly display actions
to the user, in the context of what they're working on.
The following are some examples from VsCode, Warp. These are meant to be
illustrative of what these menus already look like in the wild:
![](img/vscode-tasks-000.gif)
![](img/warp-workflows-000.gif)
The following gif was a prototype of [shell-driven autocompletion]. This was
more for suggestions from the shell, to the Terminal, but is helpful for
visualizing what this might look like in the Windows Terminal.
![](img/shell-autocomplete-jul-2022-000.gif)
A prototype of the recent commands UI, powered by shell integration:
![](img/command-history-suggestions.gif)
A prototype of the tasks UI, powered by the user's settings:
![](img/tasks-suggestions.gif)
A prototype of saving a command directly to the user's settings, then invoking it via the tasks UI
![](img/save-command.gif)
A prototype of reading tasks from the CWD
![](img/tasks-from-cwd.gif)
<hr> <!-- end of onepager -->
### Implementation Details
[TODO!]: # TODO! ---------------------------------------------------------------
What info do we all want for these tasks?
* The text to send to the terminal
- This might be multiple lines of text, with newlines in it
* A friendly description of the command (different from the name?)
* Sections of the input that are promptable, s.t. the user can save the command
as a "template", and fill it in at runtime
- ex: `nuget push -apikey az -source TerminalDependencies ${path-to-nuget-package}`
- how do we specify these as promptable sections without stomping on all sorts
of other shells syntaxes?
* ~Maybe metadata about the command that it is used for? e.g. `git`, `docker`?~
- This can probably be figured out from the first word of the command
* What shell it should be used for?
- CMD, pwsh seem like clear choices.
- linux shells are trickier - not sure Terminal can always figure out what
shell is actually running once it boots up WSL. Is it `bash`? `zsh`? `fish`?
- Running `ssh me@some-linux.box` from a CMD shell would instantly blow up
shell-specific commands
- a profile with a command-line of `cmd /k doTheThing & ssh you-get-it`, again,
would blow up the heuristic matching
- So maybe this is a **bad idea**. Maybe we should just leave tasks as "this
is just a string of text for the commandline, you gotta know which shell to
use it with"
#### Layering actions
* Fragments shouldn't be able to unbind actions from keys, _right_? TODO!
* How do we differentiate multiple actions with the same name, but different descriptions? I think everything is keyed off on Name at this point. Maybe it should be off some hash.
#### Settings comparison
##### Simple task
```pwsh
nuget push -apikey az -source TerminalDependencies ${path-to-nuget-package}
```
The JSON is pretty strightforward:
```jsonc
{
"actions":
[
{
"command":
{
"action": "sendInput",
"input": "nuget push -apikey az -source TerminalDependencies ${path-to-nuget-package}"
},
"name": "Push to nuget feed",
"description": "Used to upload a new dependency nuget to our internal nuget feed.",
},
]
}
```
The trick here is the `${path-to-nuget-package}`. PowerShell accepts the
`${foo}` syntax to mean "a variable named `foo`". So us using that in our
settings syntax would require users to escape our parsing, if they wanted to use
that syntax in powershell.
##### Multiline script
For the [following script](https://gist.github.com/zadjii-msft/b598eebd6c5601328498e3e7acc581a7):
```pwsh
$s=Invoke-GitHubGraphQlApi "query{organization(login:`"Microsoft`"){projectV2(number: 159) { id } } }"
$tasks = get-githubissue -Labels "Issue-Task" -state open
$bugs = get-githubissue -Labels "Issue-Bug" -state open
$issues = $tasks + $bugs
$issues | ? {$_.labels.Name -notcontains "Needs-Triage" } | ? { $_.milestone.title -Ne "Icebox ❄" } | ? type -Ne "PullRequest" | select -expand node_id | % {
$resp = add-githubbetaprojectitem -projectnodeid $s.organization.projectV2.id -ContentNodeId $_ ;
}
```
The JSON is basically entirely unusable. Since JSON doesn't support multiline
strings, then every line has to be joined to a single line, seperated by `\r\n`.
```jsonc
{
"actions":
[
{
"command":
{
"action": "sendInput",
"input": "$s=Invoke-GitHubGraphQlApi \"query{organization(login:`\"Microsoft`\"){projectV2(number: 159) { id } } }\"\r\n$tasks = get-githubissue -Labels \"Issue-Task\" -state open\r\n$bugs = get-githubissue -Labels \"Issue-Bug\" -state open\r\n$issues = $tasks + $bugs\r\n$issues | ? {$_.labels.Name -notcontains \"Needs-Triage\" } | ? { $_.milestone.title -Ne \"Icebox ❄\" } | ? type -Ne \"PullRequest\" | select -expand node_id | % {\r\n $resp = add-githubbetaprojectitem -projectnodeid $s.organization.projectV2.id -ContentNodeId $_ ;\r\n}"
},
"name": "Upload to project board",
"description": "Sync all our issues and bugs that have been triaged and are actually on the backlog to the big-ol project",
"shell": "pwsh",
},
]
}
```
This version instead adds a `commands` parameter to `sendInput`, with the
implication that each of these should be sent with <kbd>enter</kbd> between
them.
```jsonc
{
"actions":
[
{
"command":
{
"action": "sendInput",
"commands":
[
"$s=Invoke-GitHubGraphQlApi \"query{organization(login:`\"Microsoft`\"){projectV2(number: 159) { id } } }\"",
"$tasks = get-githubissue -Labels \"Issue-Task\" -state open",
"$bugs = get-githubissue -Labels \"Issue-Bug\" -state open",
"$issues = $tasks + $bugs",
"$issues | ? {$_.labels.Name -notcontains \"Needs-Triage\" } | ? { $_.milestone.title -Ne \"Icebox ❄\" } | ? type -Ne \"PullRequest\" | select -expand node_id | % {",
" $resp = add-githubbetaprojectitem -projectnodeid $s.organization.projectV2.id -ContentNodeId $_ ;",
"}",
""
]
},
"name": "Upload to project board",
"description": "Sync all our issues and bugs that have been triaged and are actually on the backlog to the big-ol project",
"shell": "pwsh",
},
]
}
```
Still gross, but at least maintainable.
YAML or something else might make more sense here.
#### Per-project tasks(`.wt.json`?)
In addition to tasks stored in the user's `settings.json`, we also want to provide users with a way to store commands relative to their projects. These can be checked in to source control repositories alongside code. When the
[TODO!]: # TODO! ---------------------------------------------------------------
How do we want to represent this?
* snippets of JSON with `sendInput` actions is easy for the Terminal to understand.
* They are probably not that user friendly outside of Windows Terminal.
Consider, users are gonna stick these JSON blobs in the root of their repo.
Theoretically other tools should use them too. Is our json actions syntax what
we'd really want to saddle people with?
* JSON is not super friendly to command-lines - since everything's gotta be
encapsulated as a string, then you've got to escape characters (esp quotes
`"`) for JSON strings
- on the other hand, embedding tabs `\t`, newlines `\r`, escape characters, is fairly
straightforward.
* Anything that's not JSON blobs will require a lot of spec'ing to come up with
a standard, and more expensive implementation Terminal-side
* For what it is worth, [Warp] uses .yaml files for their "workflows"[[1](#footnote-1)]. As an
example, see
[`clone_all_repos_in_org.yaml`](https://github.com/warpdotdev/workflows/blob/main/specs/git/clone_all_repos_in_org.yaml)
* Yaml does have the neat benefit of not needing too much command-line escaping
* How do we want this to play with longer workflows? E.g. our familiar [winget script]
* Markdown [Notebooks] seems relevant here, but probably not best for annotating
specific commands that we want the Terminal to pick up on. A
`.terminal-tasks.md` seems simple enough to look for, but embedding metadata
about which shell, what text should be prompted for, descriptions, that does
seem harder.
##### File name
In my original prototype, I used `.wt.json` as the filename for a
filesystem-relative commands. This seems to me like a bit of a silly file name.
Node proejcts can store various aliases for commands in their `package.json`
file. Perhaps the `.` prefix isn't necessary. Would `wt.json` be too silly?
[TODO!]: # TODO! ---------------------------------------------------------------
##### Save to project on the commandline
As an example implementation, see [these
commits](https://github.com/microsoft/terminal/compare/6f5b9fb...1cde67ac466e19394eea1eb3a41405513d160a6f).
`wt save --local commandline...`?
`wt save --settings commandline...`?
`wt save --file [path to file] commandline...`?
##### Shell escaping commandlines
Something like `wt save ping 8.8.8.8 > foo.txt` isn't going to work the way
users want. The shell is gonna get the first crack at parsing that commandline,
and is going to try and redirect the _output of `wt`_ to `foo.txt`.
<!-- This is something I encountered in #keep constantly -->
[TODO!]: # TODO! ---------------------------------------------------------------
Is there a better way to escape, like `wt save "ping 8.8.8.8 > foo.txt"` or something?
#### Community tasks from extensions
[TODO!]: # TODO! ---------------------------------------------------------------
Fragment extensions. Case in point: https://github.com/abduvik/just-enough-series/tree/master/courses/docker+docker-compose
## Tenents
<table>
<tr><td><strong>Compatibility</strong></td><td>
[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
</td></tr>
<tr><td><strong>Accessibility</strong></td><td>
[comment]: # TODO!
</td></tr>
<tr><td><strong>Sustainability</strong></td><td>
[comment]: # TODO!
</td></tr>
<tr><td><strong>Localization</strong></td><td>
[comment]: # TODO!
Mildly worried here about the potential for community-driven tasks to have
non-localized descriptions. We may need to accept a `description:{ en-us:"",
pt-br:"", ...}`-style map of language->string descriptions.
</td></tr>
</table>
[comment]: # If there are any other potential issues, make sure to include them here.
## Implementation Plan
### 🐣 Crawl
* [ ] The command palette needs to be able to display both the command name and a comment?
- This will need to be reconciled with [#7039], which tracks displaying non-localized names in the command palette
* [ ] The command palette is refactored to allow it to interact as the Tasks panel
* [ ] [#1595] An action for opening the tasks panel, filled with all `sendInput` commands
* [ ] Fragments can add **actions** to a user's settings
* [ ] [#10436] Users can manage all their fragments extensions directly in the Settings UI
### 🚶 Walk
* [ ] The terminal can look for a settings file of tasks in a profile's `startingDirectory`
* [ ] [#5790] - profile specific actions
* [ ] [#12927]
* [ ] [#12857] Ability to save selected text as a `sendInput` action
### 🏃‍♂️ Run
* [ ] When the user `cd`s to a directory (with shell integration enabled), the terminal can load the tasks from that directory tree
- Kinda dependent on [#5790] and fragment **actions**, so we understand how they should be layered.
* [ ] Fork of [#12927] - promptable sections can accept a command to dynamically populate options
### 🚀 Sprint
* [ ]
* [ ]
## Conclusion
[comment]: # Of the above proposals, which should we decide on, and why?
### Future Considerations
[comment]: # Are there other future features planned that might affect the current design of this setting? The team can help with this section during the review.
This "tasks panel" is a part of a much bigger picture. We fully intend to reuse
this for the shell-driven autocompletions that xterm.js (read:VsCode) and
PowerShell are working on (vaguely tracked by [#3121]).
Longer workflows might be best exposed as [Notebooks].
## Resources
[comment]: # Be sure to add links to references, resources, footnotes, etc.
### Footnotes
<a name="footnote-1"><a>[1]: We may want to straight up just seemlessly support that syntax. The commands are all licensed under Apache 2.0. Converting them to WT-compatible json is fairly trivial:
```python
import yaml
import json
def parse_yaml_files(directory):
json_data = {}
json_data["name"] = f"{directory} tasks..."
json_data["commands"] = []
for filename in os.listdir(directory):
if filename.endswith(".yaml") or filename.endswith(".yml"):
file_path = os.path.join(directory, filename)
with open(file_path, 'r') as file:
try:
yaml_data = yaml.safe_load(file)
new_obj = {}
command = {}
command["input"] = yaml_data["command"]
command["action"] ="sendInput"
new_obj["command"]=command
new_obj["name"] = yaml_data["name"]
new_obj["description"] = yaml_data["description"]
json_data["commands"].append(new_obj)
except yaml.YAMLError as e:
print(f"Error parsing {filename}: {e}")
json.dump(data, file, indent=4)
```
[Fig]: https://github.com/withfig/autocomplete
[Warp]: https://www.warp.dev/
[workflows]: https://docs.warp.dev/features/workflows
[also working on workflows]: https://fig.io/user-manual/workflows
[winget script]: https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
[#1595]: https://github.com/microsoft/terminal/issues/1595
[#7039]: https://github.com/microsoft/terminal/issues/7039
[#3121]: https://github.com/microsoft/terminal/issues/3121
[#10436]: https://github.com/microsoft/terminal/issues/10436
[#12927]: https://github.com/microsoft/terminal/issues/12927
[#12857]: https://github.com/microsoft/terminal/issues/12857
[#5790]: https://github.com/microsoft/terminal/issues/5790
[Notebooks]: ./Markdown%20Notebooks.md
[Terminal North Star]: ./Terminal-North-Star.md
[#keep]: https://github.com/zadjii/keep
[VsCode Tasks]: https://github.com/microsoft/terminal/blob/main/.vscode/tasks.json
<!-- TODO! -->
[shell-driven autocompletion]: ./Terminal-North-Star.md#Shell_autocompletion

View File

@@ -0,0 +1,499 @@
---
author: Mike Griese
created on: 2022-07-01
last updated: 2023-03-27
issue id: n/a
---
# Windows Terminal - Command Line North Star
## Abstract
The terminal is a critical component of Windows. It is the primary interface for
developers, system administrators, and power users. In recent years, there's
been renewed enthusiasm for the command-line environment, and new competitors on
the scene are pushing the limits of what terminals can be on other platfoms. As
a result, Microsoft recognizes the need to invest in pushing the boundaries of
terminals to enhance the user experience and remain competitive. This document
outlines the long-term strategic enhancements planned for the Windows Terminal,
with the goal of creating a more powerful and feature-rich terminal experience
that meets the evolving needs of our users.
These efforts should be considered in addition to other table-stakes
functionality. Things like improving UTF-8 support, tearing tabs out of the
window, continued expansion of VT sequence support, continued performance
improvements, and partner team asks are still important priorities. They are not
to be considered "instead of" this work, but as a fundamental baseline to this
effort. These scenarios listed below are "in addition to" the Terminal
fundamentals. Without continued investment in the fundamentals, then the north
star features here will serve only to polish a turd. Focus on fundamentals and
existing known priorities remains important to avoid mistrust generated by
questions like _"Why would they add this feature instead of working on
{fundamental issue that's existed for years}"_.
## Background
This document is a broad architectural overview of proposed features for the
Terminal. None of the scenarios listed here are described in particular detail.
Rather, the intent is to show a broad overview of how these elements work with
one another. For more detailed individual specs, refer to the following docs:
* [Notebooks]
* [Tasks]
* [Suggestions UI]
* [Copilot]
* [Shell Integration]
### Context
This document was originally authored in 2022, in the midst of the ongoing
global COVID-19 pandemic. At the time, one of the key focuses of the tech
industry was ways to empower remote collaboration. The reader will find a number
of scenarios that are heavily influenced by this. While the pandemic has begun
to recede, and companies are returning to the office in greater numbers, it
remains an important mission to support collaboration in whatever form it might
take.
Subsequently, recent advances in large language models have made "AI"
experiences more reliable and convincing. This has created the opportunity to
build new experiences powered by these "AI" models. Further additions were made
to this doc to reflect these advancements. While these language models can
provide powerful new experiences, it remains important that we continue to
prioritize ["human intelligence", enhanced by
AI](#addenda-human-intelligence-and-artificial-intelligence).
## Pillars
This document focuses on a few key scenarios which are more revolutionary
feature adds rather than "table stakes" features the Terminal has been focused
on for the last few years. These are grouped into the following pillars:
* Command-line tooling is easier to discover and use
* The Terminal advances the command-line shell UX
* The Terminal enables new CLI experiences
* The Terminal enables powerful collaboration
* The Terminal provides a first-class accesibility experience
### Command-line tooling is easier to discover and use
(_The Terminal makes my existing command-line workflow better_)
* AI enables users to describe what they want to do with the commandline, rather
than relying on user's knowledge of specific commands and arguments. <!-- D -->
* AI can quickly provide explanations of what's happening - error messages and
command lines can be explained without needing to leave the context of the
Terminal. <!-- D -->
* Markdown integration for quickly running blocks of commands from existing
markdown documentation <!-- E -->
* Recording the contents of the Terminal output to a file is simple and
optimized for sharing on GitHub <!-- F -->
* Searching for errors is as simple as right clicking on some selected text
<!-- * Customizations to command-line tools is easy to discover and install ~The
Terminal exposes a curated list of ways to customize your command-line
tooling, and easily install~ -->
<!-- * Working across multiple machines is made easy
* Automatic detection of saved ssh sessions and Hyper-V VMs makes connecting simple
* Broadcasting input to multiple tabs and panes makes exectuting the same
commands in multiple environments easy -->
### The Terminal advances the command-line shell UX
(_Things the Terminal can do for the user, to provide a modern experience_)
* Prompts, command-lines, output are marked semantically <!-- A -->
* Icons in the gutter to indicate if a command succeeded, had an error, or was canceled <!-- A -->
* Icons in the gutter can be used to quickly: <!-- A -->
* re-run the command
* copy the output to the clipboard
* Save the command line as an action for later.
* Horizontal markers can be used to subtly indicate the separation between different commands <!-- A -->
* The terminal remembers command-lines ("Tasks") <!-- B -->
* Users can share complicated command-lines with one another for easy access
* Errors and warnings in output can be automatically identified and jumped to <!-- A -->
### The Terminal enables new CLI experiences
(_New experiences that CLI applications can deliver for users_)
* CLI apps can drive rich auto-complete suggestions presented by the Terminal <!-- C -->
* CLI applications can send Windows notifications via the Terminal
* CLI apps can display images in the Terminal (sixel)
* CLI apps can provide clickable suggestions <!-- ala https://github.com/microsoft/terminal/issues/5001#issuecomment-1246562464 -->
### The Terminal enables powerful collaboration
* LiveShare - share a terminal window with a member of your team for realtime collaboration
* Useful commands and notes can be shared automatically across members of your team
### The Terminal provides a first-class accesibility experience
* Terminals can describe their contents prcatically to assistive technologies, through a new "terminal" UIA pattern <!-- (word delims, alt/main buffer) -->
* CLI apps can help direct the behavior of screen readers, via new VT sequences
* High Contrast Mode within the Terminal itself adjusts text colors to make sure all CLI apps are visible.
* CLI apps can provide auto-completions which the Terminal can use to present rich details to screen readers <!-- C -->
## Business Justification
**"The command line works best on Windows"**. Your shells, your tools, don't
just work, but work _best_ on Windows, enabled by enhancements provided by the
Windows Terminal.
The Terminal remains the primary dev environment for developers of all sorts of
toolchains. It remains the most familiar experience for users who are
considering Windows over MacOS or linux.
The terminal is a deeply personal app. Users spend a lot of time adjusting their
terminal of choice to fit their needs. Once users find one they like, they're
unlikely to change. Developers are highly opinionated. One-size-fits-all
solutions are typically not good enough. Every developer has their own opinions
on how they'd like their keybindings, what colors they'd like to use, what shell
or editor is best. By providing the most customizable terminal possible, we
address the largest possible cohort of developers. Giving developers knobs for
every possible setting removes any incentive for developers to seek out an
alternative.
There's plenty of interest in reinvigorating the command line experience.
Applications like [Fig] and [Warp] demonstrate the desire for not just incremental
improvements to the user experience of the command-line, but wholesale
reimagining. To date, the Windows Terminal has managed to meet current
expectations of terminals on other platforms (and remains short of competitiors,
like ITerm2, in many regards).
For some market comparison - Warp raised $26M of funding, and Fig raised $2.4M.
That's 28 million combined dollars of investment into the command-line
experience, which at this point was only produced tooling for MacOS.
These "Hero scenarios" create a compelling differentiating experience on
Windows. They position Windows as the premier command line development
experience. By providing the best-in-class developer experience, we seek to
provide an ecosystem where developers would be reluctant to choose another
platform. Scenarios here help create an ecosystem of features surrounding the
Terminal, features which aren't immediately reproducible on other platforms.
## Scenario Details
Above is listed a high-level description of some user stories. This section
provides a deeper drill into some of the above areas.
### Scenario A: More powerful commanding powered by advanced shell integration
The Terminal provides a way for command line shells to semantically mark parts
of the command-line output. By marking up parts of the output, the Terminal can
richer experiences. The Terminal will know where each command starts and stops,
what the actual command was and what the output of that command is. This allows
the terminal to expose quick actions for:
* Quickly navigating the history by scrolling between commands
* Re-running a previous command in the history
* Copying all the output of a single command-line
* A visual indicator to separate out one command-line from the next, for quicker
mental parsing of the output of the command-line.
* Collapsing the output of a command, as to reduce noise
* Visual indicators that highlight commands that succeeded or failed.
* Jumping to previously used directories
Enabling these features requires that the shell co-operates with the terminal,
to tell the Terminal about these parts of the output. Typically, this would
require complicated customizations that the user would have to install manually
into their shell's configuration. We will provide sample snippets that will
enable this functionality for a variety of shells. However, VsCode has
experimented with functionality to automatically insert this functionality into
shells it's familiar with. This has been reasonably successful to date, so it
provides a valuable guide for a way the Terminal could do the same. This would
enable the Terminal to have a simple setting that would automatically enable
powerful features for the user's shell, without them needing to configure their
shell at all.
### Scenario B: The Terminal knows and remembers complicated command lines, so I don't have to
The command line experience is often filled with running a number of commands
with some frequency, but also a small number of commands infrequently.
Command-line options and parameters are not easily discoverable, forcing
developers to constantly refer back to documentation. Team members often need to
use the same command-lines within the scope of their project, but need to share
them amongst the team manually.
Users might run a series of commands like `git commit -m "..."`, `git push`
multiple times an hour. For these kinds of scenarios, it might be helpful if the
commands were easily accessible with a single keystroke, rather than typing them
out every single time.
Other commands the user might run once a month, or even less frequently. Some
projects might have a very complicated command-line for pushing an updated
package to nuget, which the developer only needs to run once every few months.
That kind of infrecuency leads to the developer needing to look up the command
from their notes every time, if the notes even exist. Consider a single
developer working on the OS repo, who might work in a variety of projects within
that repo. They might need to bounce around between projects every couple
months. Each project might have its own build scripts, test deployment scripts,
and output files that are interesting. Without good notes, it would be easy for
the developer to simply forget the commands for a single project in the months
between working on it.
Similarly, there are scenarios where one member of a team might author a
complicated command-line for doing something in their project. ~As an example -
sometimes a local clone of the Terminal repo can get into a broken state where a
user needs to delete a couple `.xbf` files, but just blindly deleting them all
would force a full rebuild. I've got a handy script that just deletes the bad
ones, but any time someone on the team needs this they need to go where? Our
wiki? Our OneNote? Somewhere deep in the Teams chat history?~ Now, that
developer needs to share it manually with the rest of the team. The team would
need to have a well documented way of sharing command-lines between members - a
practice that surely not every team has mastered.
Furthermore, there is often a discommect between what the user wants to do, and
what the user needs to type at a command-line. Consider "I need to compress this
directory to a `tar.gz` archive". The user knows what they want to do, but they
now need to go pull up a man page or Stack Overflow to figure out how to do what
they want.
Enter **[Tasks]**. These are sets of command-lines that can quickly
be saved, shared, with descriptive names and longer descriptions. They can be
grouped - by application, by team, by whatever the user chooses. Descriptive
names allow users to quickly navigate the menu looking for the thing they want
to do. When shared to your team{repo/project/?}, they automatically show up for
other team members.
After running a command in your shell that you'd like to save for later, all it
takes is a simple <kbd>↑</kbd>, <kbd>Home</kbd>, `wt save `, and the terminal will stash that
command-line for later use.
Tasks are powered by the [Suggestions UI].
### Scenario C: The Terminal enables powerful autocompletion suggestions, driven by the shell
Shells are already powerful tools in their own right. Anyone who's used a shell
more than a few times is probably familiar with shells' ability to tab-complete
paths at the prompt. Most modern shells provide elaborate mechanisms for command
line apps to extend their tab completion, so that subcommands, arguments, and
parameter values can also be tab-completed. However, these options are not
usually highly discoverable - the completions the shell might provide still
assume the user hast started typing the correct value.
PowerShell has started to attempt to mitigate this with its MenuComplete, which
outputs possible suggestions beneath the prompt inline with other commandline
output. Other shells (like `fish`, `zsh`) have similar extensions as well.
However, everyone needs to implement support for these menus themselves.
One major downside of this is that these menus are very hard for screen readers
to interact with. The mechanism used to redraw parts of the "menu" to indicate
the selection changed usually means that a screen reader will re-read the entire
menu of suggestions. Furthermore, there's no way for a screen reader to indicate
the purpose of this text.
To remedy this, we'll implement a new VT escape sequence. This sequence can be
used by a CLI application to tell the terminal to render a menu of suggestions.
This will enable the Terminal to present all the options the shell knows about
to the user in a quickly filterable menu. By being a dedicated control within
the Terminal, the Terminal can provide unique UIA patterns for this menu to make
it clear to screen readers what is happening.
By authoring this as a open VT standard, we enable not just Terminal and
PowerShell to use this to communicate with one another, but any combination of
terminal and CLI application. The ecosystem works best when we all work
together. Prototypes for this protocol and menu were started by the VsCode
terminal's team. Both VsCode and Terminal can reuse the same plumbing, as well
as `xterm`, `alacritty`, `gnome-terminal` or anything else out there.
Shell autocompletion is powered by the [Suggestions UI].
### Scenario D: AI powered commandline experience
Recent advancements in large language models have created a rapidy evolving
ecosystem of AI-enhanced experiences. These models are highly effective at
synthesizing responses to natural language questions. The command line is no
different, and is an environment ripe for innovation.
The commandline is an environment filled with verbose, often esoteric output.
This is a place where AI might be valuable for translating those error messages
to simple language explaining what went wrong.
In the reverse, translating natural language descriptions of what the user wants
to do into actual commands is a well-trodden path for innovation. In only the
few months since the broad rollout of gpt-3 and Github Copilot, already there
are many examples of "natural language to commandline". There's already [Codex
CLI], [Copilot CLI], and [Warp AI] all working on natural language experiences
in the terminal.
These are just two key scenarios we're targeting. This is a space where the
current pace of innovation is very rapid. The landscape of what models are
available and what they are capable is evolving weekly. Staying on top of these
innovations and finding ways to integrate these experiences into the Terminal
will be an important part of our strategy moving forward.
Crucially, we'll want to create a pluggable infrastructure for these AI
features. This will enable developers to pick and choose whatever model they
prefer. The Terminal will ask simple, abstract queries from these plugins, and
leave the prompting implementation to the actual plugin author themselves. This
will allow the greatest flexibility for experimentation on both the part of the
Terminal and the model backend itself. The Terminal won't need to concern itself
with the raw prompt construction. The plugin authors will be able to experiment
and fine-tune their prompts to get the best results.
This scenario is discussed in greater detail in [Copilot] and the specs in that
directory.
### Scenario E: Markdown notebooks
Notebooks have risen to popularity in recent years as a way of combining both
code and documentation in a single experience. They enable users to seamlessly
write code, and execute it to see the output, write documentation on the code,
and share that with others. However, there's not really anything like notebooks
for generic commandline experiences.
There are, however, markdown files. Markdown has become a bit of a lingua franca
of the developer experience. It's used prominently on GitHub - the "homepage" of
any repo on GitHub is now typically a markdown file. This file will have all
sorts of documentation, and notably these READMEs are often filled with commands
that one can execute for this project. Downloading, installing its dependencies,
building and running the project, etc, all commands that are already listed
today in READMEs across the world.
It would be a major convenience for users to be able to just load a pre-rendered
markdown file directly into their terminal windows. These files already include
marked blocks of code which identify sets of commands for the command line. It
should be as simple as clicking a button to run these commands in the Terminal,
or even to run a whole file worth of commands automatically.
This scenario is discussed in greater detail in [Notebooks] and the specs in that
directory.
<!--
Omitted from North Star - these are valuable features, but not pushing the
boundary of what's possible by terminal emulators today
### Scenario W: Enhancements to remote connections
* Dynamic profiles from `.sshconfig`
* [#12773] Dynamic profiles from Hyper-V VMs
* Broadcast Input Mode
* -->
### Scenario F: Quick Terminal recording
Case in point: [Textualize]. This is a website that's loaded with recordings of
the terminal doing something cool. And they're all using **macOS**. That
reinforces the precedent that cool command line experiences are being developed
for _not Windows_.
Gifs that could easily be shared in READMEs on GitHub, where developers
already frequently use recordings of their terminal to demonstrate how their
tools work. By including not just the body of the Terminal, but the frame
itself, it's immediately apparent to someone watching that _this is the Windows
Terminal_. The observer knows that this gif was recoded on Windows, and that the
maintainer built this tool on Windows (and ideally, for Windows). By making the
experience as quick and painless as possible, developers could quickly create
engaging documentation for their users.
## UI/UX Design
Below are some screenshots of similar features from other apps. Featured here prominently are iTerm2, Warp, and VsCode's own xterm.js.
### Prior art
#### Workflows, suggestions
![Warp's Workflows](img/warp-workflows-001.gif)
![iTerm2's Command History toolbox](img/iterm2-CommandHistory.png)
#### Shell autocompletion
![](img/vscode-shell-autocomplete-000.gif)
![](img/shell-autocomplete-jul-2022-000.gif)
#### Notebooks
![](img/jupyter-notebooks-example.png)
## Conclusion
Investing engineering resources into pushing the boundaries of the Terminal is a
critical strategy that will benefit Windows and Microsoft as a whole. By
providing new user experiences and capabilities, we can boost the entire Windows
ecosystem. A more powerful terminal will attract developers to build new and
innovative applications for Windows, making the platform more vibrant and
exciting. By leveraging our connected services via Visual Studio, GitHub, and AI
we can create a more compelling and attractive platform to better serve the
needs of our users. This robust developer experience will help Windows stand out
as the best platform for developers and system administrators.
<!-- ### Future Considerations
[comment]: # Are there other future features planned that might affect the current design of this setting? The team can help with this section during the review. -->
## Resources
This architecture docs is intentionally a 10000ft overview. For more detailed docs on these scenarios, see the following docs:
* [Notebooks]
* [Tasks]
* [Suggestions UI]
* [Copilot]
* [Shell Integration]
## Addenda: Human Intelligence and Artificial Intelligence
An ongoing theme within the tech industry is how AI can empower user with new
experiences. I think it is important to remember that Human Intelligence should
always be relied upon first and foremost. AI can be a useful backstop for human
intelligence, but it is no replacement. Whenever possible, we should rely on the
user's own knowledge and expertise, before using AI for suggestions.
As an example: Tasks and AI Command Suggestions. Tasks are usually a better
answer for the user - they represent the user has already found the answer of
how to do something. They've already evaluated that task as the correct solution
to the problem. Tasks that are shared with the rest of your team are similar - a
team mate has already found the right solution for a problem within your
project. Their solution is going to be more reliable than asking a language
model to synthesize a result.
AI can be used to enhance human intelligence, when at the limits of the user's
knowledge. Large language models can be used to produce results that are
sometimes correct and often incorrect. They're best at synthesizing results the
user could have otherwise found in a web search or in documentation. Providing
immediate access to those answers helps the user stay in the flow. For more
challenging queries that the model may not have exact, correct responses for,
even wrong responses can be valuable. They can help to inspire human creativity.
A wrong response might help point the user in the direction of the correct
solution.
## Addenda: Command-line North Star
This document is solely Terminal-oriented. Everything in here is features that
the Terminal can provide to improve the developer experience on Windows. What's
not covered at all are ways we can improve the commandline tooling itself on
Windows. Things like adding more built-in commandline utilities. Updating
existing ones (`tar`, `curl`). There's no discussion of improvements to our
shell offerings (`cmd` or PowerShell). This is another valuable discussion we
should have, but I feel it warrants its own doc.
## Addenda: Shell Integration metrics from VsCode
In the first month that Shell Integration was enabled by default for all VsCode users:
* ~57% machines fired shell integration-related events (_I think this covers all
who used the terminal_). Of those:
* 40% succeeded activation at least once
* 83% failed activation silently/gracefully at least once (_This improved in subsequent releases_)
* 0.2% Failed due to process exit (_This was likely mostly https://github.com/microsoft/vscode/issues/157611_)
* ~0.4% changed the setting manually to true or false
That last number, 0.4%, would suggest that the number of people who opted out is
_very_ low and that the feature would be largely inoffensive.
### Footnotes
<a name="footnote-1"><a>[1]:
[Fig]: https://github.com/withfig/autocomplete
[Warp]: https://www.warp.dev/
[#13445]: https://github.com/microsoft/terminal/issues/13445
[Textualize]: https://www.textualize.io/
[#12773]: https://github.com/microsoft/terminal/issues/12773
[Notebooks]: ./Markdown%20Notebooks.md
[Tasks]: ./Tasks.md
[Suggestions UI]: ./Suggestions-UI.md
[Shell Integration]: ./Shell-Integration-Marks.md
[Copilot]: ./Copilot/Overview.md
[Codex CLI]: https://github.com/microsoft/Codex-CLI
[Copilot CLI]: https://githubnext.com/projects/copilot-cli/
[Warp AI]: https://docs.warp.dev/features/warp-ai

View File

@@ -0,0 +1,8 @@
@echo off
pushd .
cd Copilot
pandoc -s Overview.md -o ..\generated\Copilot\Overview.docx
pandoc -s Prompting.md -o ..\generated\Copilot\Prompting.docx
pandoc -s Implicit-Suggestions.md -o ..\generated\Copilot\Implicit-Suggestions.docx
pandoc -s Explain-that.md -o ..\generated\Copilot\Explain-that.docx
popd

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB