Merged PR 5193669: Migrate OSS up to 468c8c672

Chester Liu (1)
* Preprocess and convert C1 controls to their 7 bit equivalent  (CC-7340)

Related work items: MSFT-29480515
This commit is contained in:
Dustin Howett 2020-09-18 19:03:47 +00:00
commit a13a7c3948
32 changed files with 836 additions and 1334 deletions

View file

@ -3,6 +3,7 @@ ACCESSDENIED
alignof
bitfield
bitfields
COLORPROPERTY
CLASSNOTAVAILABLE
environstrings
EXPCMDFLAGS

View file

@ -20937,6 +20937,8 @@ apay
Apayao
APB
APC
Apc
apc
APDA
APDU
APE
@ -383889,6 +383891,7 @@ sorus
sorva
sory
SOS
Sos
sos
Sosanna
so-seeming

View file

@ -1,211 +1 @@
# Settings.json Documentation
## Globals
Properties listed below affect the entire window, regardless of the profile settings.
| Property | Necessity | Type | Default | Description |
| -------- | --------- | ---- | ------- | ----------- |
| `alwaysShowTabs` | _Required_ | Boolean | `true` | When set to `true`, tabs are always displayed. When set to `false` and `showTabsInTitlebar` is set to `false`, tabs only appear after typing <kbd>Ctrl</kbd> + <kbd>T</kbd>. |
| `copyOnSelect` | Optional | Boolean | `false` | When set to `true`, a selection is immediately copied to your clipboard upon creation. When set to `false`, the selection persists and awaits further action. |
| `copyFormatting` | Optional | Boolean, Array | `true` | When set to `true`, the color and font formatting of selected text is also copied to your clipboard. When set to `false`, only plain text is copied to your clipboard. An array of specific formats can also be used. Supported array values include `html` and `rtf`. Plain text is always copied. |
| `largePasteWarning` | Optional | Boolean | `true` | When set to `true`, trying to paste text with more than 5 KiB of characters will display a warning asking you whether to continue or not with the paste. |
| `multiLinePasteWarning` | Optional | Boolean | `true` | When set to `true`, trying to paste text with a _new line_ character will display a warning asking you whether to continue or not with the paste. |
| `defaultProfile` | _Required_ | String | PowerShell guid | Sets the default profile. Opens by typing <kbd>Ctrl</kbd> + <kbd>T</kbd> or by clicking the '+' icon. The guid of the desired default profile is used as the value. |
| `initialCols` | _Required_ | Integer | `120` | The number of columns displayed in the window upon first load. |
| `initialPosition` | Optional | String | `","` | The position of the top left corner of the window upon first load. On a system with multiple displays, these coordinates are relative to the top left of the primary display. If `launchMode` is set to `"maximized"`, the window will be maximized on the monitor specified by those coordinates. |
| `initialRows` | _Required_ | Integer | `30` | The number of rows displayed in the window upon first load. |
| `launchMode` | Optional | String | `default` | Defines whether the Terminal will launch as maximized or not. Possible values: `"default"`, `"maximized"` |
| `theme` | _Required_ | String | `system` | Sets the theme of the application. Possible values: `"light"`, `"dark"`, `"system"` |
| `showTerminalTitleInTitlebar` | _Required_ | Boolean | `true` | When set to `true`, titlebar displays the title of the selected tab. When set to `false`, titlebar displays "Windows Terminal". |
| `showTabsInTitlebar` | Optional | Boolean | `true` | When set to `true`, the tabs are moved into the titlebar and the titlebar disappears. When set to `false`, the titlebar sits above the tabs. |
| `snapToGridOnResize` | Optional | Boolean | `false` | When set to `true`, the window will snap to the nearest character boundary on resize. When `false`, the window will resize "smoothly" |
| `tabWidthMode` | Optional | String | `equal` | Sets the width of the tabs. Possible values: <br><ul><li>`"equal"`: sizes each tab to the same width</li><li>`"titleLength"`: sizes each tab to the length of its title</li><li>`"compact"`: sizes each tab to the length of its title when focused, and shrinks to the size of only the icon when the tab is unfocused.</li></ul> |
| `wordDelimiters` | Optional | String | <code>&nbsp;&#x2f;&#x5c;&#x28;&#x29;&#x22;&#x27;&#x2d;&#x3a;&#x2c;&#x2e;&#x3b;&#x3c;&#x3e;&#x7e;&#x21;&#x40;&#x23;&#x24;&#x25;&#x5e;&#x26;&#x2a;&#x7c;&#x2b;&#x3d;&#x5b;&#x5d;&#x7b;&#x7d;&#x7e;&#x3f;</code><br>_(`│` is `U+2502 BOX DRAWINGS LIGHT VERTICAL`)_ | Determines the delimiters used in a double click selection. |
| `confirmCloseAllTabs` | Optional | Boolean | `true` | When set to `true` closing a window with multiple tabs open WILL require confirmation. When set to `false` closing a window with multiple tabs open WILL NOT require confirmation. |
| `startOnUserLogin` | Optional | Boolean | `false` | When set to `true` enables the launch of Windows Terminal at startup. Setting to `false` will disable the startup task entry. Note: if the Windows Terminal startup task entry is disabled either by org policy or by user action this setting will have no effect. |
| `disabledProfileSources` | Optional | Array[String] | `[]` | Disables all the dynamic profile generators in this list, preventing them from adding their profiles to the list of profiles on startup. This array can contain any combination of `Windows.Terminal.Wsl`, `Windows.Terminal.Azure`, or `Windows.Terminal.PowershellCore`. For more information, see [UsingJsonSettings.md](https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md#dynamic-profiles) |
| `experimental.rendering.forceFullRepaint` | Optional | Boolean | `false` | When set to true, we will redraw the entire screen each frame. When set to false, we will render only the updates to the screen between frames. |
| `experimental.rendering.software` | Optional | Boolean | `false` | When set to true, we will use the software renderer (a.k.a. WARP) instead of the hardware one. |
## Profiles
Properties listed below are specific to each unique profile.
| Property | Necessity | Type | Default | Description |
| -------- | --------- | ---- | ------- | ----------- |
| `guid` | _Required_ | String | | Unique identifier of the profile. Written in registry format: `"{00000000-0000-0000-0000-000000000000}"`. |
| `name` | _Required_ | String | | Name of the profile. Displays in the dropdown menu. <br>Additionally, this value will be used as the "title" to pass to the shell on startup. Some shells (like `bash`) may choose to ignore this initial value, while others (`cmd`, `powershell`) may use this value over the lifetime of the application. This "title" behavior can be overridden by using `tabTitle`. |
| `acrylicOpacity` | Optional | Number | `0.5` | When `useAcrylic` is set to `true`, it sets the transparency of the window for the profile. Accepts floating point values from 0-1. |
| `antialiasingMode` | Optional | String | `"grayscale"` | Controls how text is antialiased in the renderer. Possible values are "grayscale", "cleartype" and "aliased". Note that changing this setting will require starting a new terminal instance. |
| `background` | Optional | String | | Sets the background color of the profile. Overrides `background` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
| `backgroundImage` | Optional | String | | Sets the file location of the Image to draw over the window background. |
| `backgroundImageAlignment` | Optional | String | `center` | Sets how the background image aligns to the boundaries of the window. Possible values: `"center"`, `"left"`, `"top"`, `"right"`, `"bottom"`, `"topLeft"`, `"topRight"`, `"bottomLeft"`, `"bottomRight"` |
| `backgroundImageOpacity` | Optional | Number | `1.0` | Sets the transparency of the background image. Accepts floating point values from 0-1. |
| `backgroundImageStretchMode` | Optional | String | `uniformToFill` | Sets how the background image is resized to fill the window. Possible values: `"none"`, `"fill"`, `"uniform"`, `"uniformToFill"` |
| `closeOnExit` | Optional | String | `graceful` | Sets how the profile reacts to termination or failure to launch. Possible values: `"graceful"` (close when `exit` is typed or the process exits normally), `"always"` (always close) and `"never"` (never close). `true` and `false` are accepted as synonyms for `"graceful"` and `"never"` respectively. |
| `colorScheme` | Optional | String | `Campbell` | Name of the terminal color scheme to use. Color schemes are defined under `schemes`. |
| `commandline` | Optional | String | | Executable used in the profile. |
| `cursorColor` | Optional | String | | Sets the cursor color of the profile. Overrides `cursorColor` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
| `cursorHeight` | Optional | Integer | | Sets the percentage height of the cursor starting from the bottom. Only works when `cursorShape` is set to `"vintage"`. Accepts values from 25-100. |
| `cursorShape` | Optional | String | `bar` | Sets the cursor shape for the profile. Possible values: `"vintage"` ( &#x2583; ), `"bar"` ( &#x2503; ), `"underscore"` ( &#x2581; ), `"filledBox"` ( &#x2588; ), `"emptyBox"` ( &#x25AF; ) |
| `fontFace` | Optional | String | `Cascadia Mono` | Name of the font face used in the profile. We will try to fallback to Consolas if this can't be found or is invalid. |
| `fontSize` | Optional | Integer | `12` | Sets the font size. |
| `fontWeight` | Optional | String | `normal` | Sets the weight (lightness or heaviness of the strokes) for the given font. Possible values: `"thin"`, `"extra-light"`, `"light"`, `"semi-light"`, `"normal"`, `"medium"`, `"semi-bold"`, `"bold"`, `"extra-bold"`, `"black"`, `"extra-black"`, or the corresponding numeric representation of OpenType font weight. |
| `foreground` | Optional | String | | Sets the foreground color of the profile. Overrides `foreground` set in color scheme if `colorscheme` is set. Uses hex color format: `#rgb` or `"#rrggbb"`. |
| `hidden` | Optional | Boolean | `false` | If set to true, the profile will not appear in the list of profiles. This can be used to hide default profiles and dynamically generated profiles, while leaving them in your settings file. |
| `historySize` | Optional | Integer | `9001` | The number of lines above the ones displayed in the window you can scroll back to. |
| `icon` | Optional | String | | Image file location of the icon used in the profile. Displays within the tab and the dropdown menu. |
| `padding` | Optional | String | `8, 8, 8, 8` | Sets the padding around the text within the window. Can have three different formats: `"#"` sets the same padding for all sides, `"#, #"` sets the same padding for left-right and top-bottom, and `"#, #, #, #"` sets the padding individually for left, top, right, and bottom. |
| `scrollbarState` | Optional | String | `"visible"` | Defines the visibility of the scrollbar. Possible values: `"visible"`, `"hidden"` |
| `selectionBackground` | Optional | String | | Sets the selection background color of the profile. Overrides `selectionBackground` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
| `snapOnInput` | Optional | Boolean | `true` | When set to `true`, the window will scroll to the command input line when typing. When set to `false`, the window will not scroll when you start typing. |
| `altGrAliasing` | Optional | Boolean | `true` | By default Windows treats Ctrl+Alt as an alias for AltGr. When altGrAliasing is set to false, this behavior will be disabled. |
| `source` | Optional | String | | Stores the name of the profile generator that originated this profile. _There are no discoverable values for this field._ |
| `startingDirectory` | Optional | String | `%USERPROFILE%` | The directory the shell starts in when it is loaded. |
| `suppressApplicationTitle` | Optional | Boolean | `false` | When set to `true`, `tabTitle` overrides the default title of the tab and any title change messages from the application will be suppressed. When set to `false`, `tabTitle` behaves as normal. |
| `tabTitle` | Optional | String | | If set, will replace the `name` as the title to pass to the shell on startup. Some shells (like `bash`) may choose to ignore this initial value, while others (`cmd`, `powershell`) may use this value over the lifetime of the application. |
| `useAcrylic` | Optional | Boolean | `false` | When set to `true`, the window will have an acrylic background. When set to `false`, the window will have a plain, untextured background. The transparency only applies to focused windows due to OS limitation. |
| `experimental.retroTerminalEffect` | Optional | Boolean | `false` | When set to `true`, enable retro terminal effects. This is an experimental feature, and its continued existence is not guaranteed. |
## Schemes
Properties listed below are specific to each color scheme. [ColorTool](https://github.com/microsoft/terminal/tree/master/src/tools/ColorTool) is a great tool you can use to create and explore new color schemes. All colors use hex color format.
| Property | Necessity | Type | Description |
| -------- | ---- | ----------- | ----------- |
| `name` | _Required_ | String | Name of the color scheme. |
| `foreground` | _Required_ | String | Sets the foreground color of the color scheme. |
| `background` | _Required_ | String | Sets the background color of the color scheme. |
| `selectionBackground` | Optional | String | Sets the selection background color of the color scheme. |
| `cursorColor` | Optional | String | Sets the cursor color of the color scheme. |
| `black` | _Required_ | String | Sets the color used as ANSI black. |
| `blue` | _Required_ | String | Sets the color used as ANSI blue. |
| `brightBlack` | _Required_ | String | Sets the color used as ANSI bright black. |
| `brightBlue` | _Required_ | String | Sets the color used as ANSI bright blue. |
| `brightCyan` | _Required_ | String | Sets the color used as ANSI bright cyan. |
| `brightGreen` | _Required_ | String | Sets the color used as ANSI bright green. |
| `brightPurple` | _Required_ | String | Sets the color used as ANSI bright purple. |
| `brightRed` | _Required_ | String | Sets the color used as ANSI bright red. |
| `brightWhite` | _Required_ | String | Sets the color used as ANSI bright white. |
| `brightYellow` | _Required_ | String | Sets the color used as ANSI bright yellow. |
| `cyan` | _Required_ | String | Sets the color used as ANSI cyan. |
| `green` | _Required_ | String | Sets the color used as ANSI green. |
| `purple` | _Required_ | String | Sets the color used as ANSI purple. |
| `red` | _Required_ | String | Sets the color used as ANSI red. |
| `white` | _Required_ | String | Sets the color used as ANSI white. |
| `yellow` | _Required_ | String | Sets the color used as ANSI yellow. |
## Keybindings
Properties listed below are specific to each custom key binding.
| Property | Necessity | Type | Description |
| -------- | ---- | ----------- | ----------- |
| `command` | _Required_ | String | The command executed when the associated key bindings are pressed. |
| `keys` | _Required_ | Array[String] or String | Defines the key combinations used to call the command. |
| `action` | Optional | String | Adds additional functionality to certain commands. |
### Implemented Commands and Actions
Commands listed below are per the implementation in [`src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp).
Keybindings can be structured in the following manners:
For commands without arguments:
<br>
`{ "command": "commandName", "keys": [ "modifiers+key" ] }`
For commands with arguments:
<br>
`{ "command": { "action": "commandName", "argument": "value" }, "keys": ["modifiers+key"] }`
| Command | Command Description | Action (*=required) | Action Arguments | Argument Descriptions |
| ------- | ------------------- | ------ | ---------------- | ----------------- |
| `adjustFontSize` | Change the text size by a specified point amount. | `delta` | integer | Amount of size change per command invocation. |
| `closePane` | Close the active pane. | | | |
| `closeTab` | Close the current tab. | | | |
| `closeWindow` | Close the current window and all tabs within it. | | | |
| `copy` | Copy the selected terminal content to your Windows Clipboard. | 1. `singleLine`<br>2. `copyFormatting` | 1. boolean<br>2. boolean, array | 1. When `true`, the copied content will be copied as a single line. When `false`, newlines persist from the selected text.<br>2. When set to `true`, the color and font formatting of selected text is also copied to your clipboard. When set to `false`, only plain text is copied to your clipboard. An array of specific formats can also be used. Supported array values include `html` and `rtf`. Plain text is always copied. Not setting this value inherits the behavior of the `copyFormatting` global setting. |
| `duplicateTab` | Make a copy and open the current tab. | | | |
| `find` | Open the search dialog box. | | | |
| `moveFocus` | Focus on a different pane depending on direction. | `direction`* | `left`, `right`, `up`, `down` | Direction in which the focus will move. |
| `newTab` | Create a new tab. Without any arguments, this will open the default profile in a new tab. | 1. `commandLine`<br>2. `startingDirectory`<br>3. `tabTitle`<br>4. `index`<br>5. `profile` | 1. string<br>2. string<br>3. string<br>4. integer<br>5. string | 1. Executable run within the tab.<br>2. Directory in which the tab will open.<br>3. Title of the new tab.<br>4. Profile that will open based on its position in the dropdown (starting at 0).<br>5. Profile that will open based on its GUID or name. |
| `nextTab` | Open the tab to the right of the current one. | | | |
| `openNewTabDropdown` | Open the dropdown menu. | | | |
| `openSettings` | Open the settings file. | | | |
| `paste` | Insert the content that was copied onto the clipboard. | | | |
| `prevTab` | Open the tab to the left of the current one. | | | |
| `resetFontSize` | Reset the text size to the default value. | | | |
| `resizePane` | Change the size of the active pane. | `direction`* | `left`, `right`, `up`, `down` | Direction in which the pane will be resized. |
| `scrollDown` | Move the screen down. | | | |
| `scrollUp` | Move the screen up. | | | |
| `scrollUpPage` | Move the screen up a whole page. | | | |
| `scrollDownPage` | Move the screen down a whole page. | | | |
| `sendInput` | Sends some text input to the shell. | `input` | string | The text input to feed into the shell.<br>ANSI escape sequences may be used. Escape codes like `\x1b` must be written as `\u001b`.<br>For instance the input `"text\n"` will write "text" followed by a newline. `"\u001b[D"` will behave as if the left arrow button had been pressed. |
| `splitPane` | Halve the size of the active pane and open another. Without any arguments, this will open the default profile in the new pane. | 1. `split`*<br>2. `commandLine`<br>3. `startingDirectory`<br>4. `tabTitle`<br>5. `index`<br>6. `profile`<br>7. `splitMode` | 1. `vertical`, `horizontal`, `auto`<br>2. string<br>3. string<br>4. string<br>5. integer<br>6. string<br>7. string | 1. How the pane will split. `auto` will split in the direction that provides the most surface area.<br>2. Executable run within the pane.<br>3. Directory in which the pane will open.<br>4. Title of the tab when the new pane is focused.<br>5. Profile that will open based on its position in the dropdown (starting at 0).<br>6. Profile that will open based on its GUID or name.<br>7. Controls how the pane splits. Only accepts `duplicate` which will duplicate the focused pane's profile into a new pane. |
| `switchToTab` | Open a specific tab depending on index. | `index`* | integer | Tab that will open based on its position in the tab bar (starting at 0). |
| `toggleFullscreen` | Switch between fullscreen and default window sizes. | | | |
| `unbound` | Unbind the associated keys from any command. | | | |
### Accepted Modifiers and Keys
#### Modifiers
`ctrl+`, `shift+`, `alt+`
#### Keys
| Type | Keys |
| ---- | ---- |
| Function and Alphanumeric Keys | `f1-f24`, `a-z`, `0-9` |
| Symbols | ``` ` ```, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/` |
| Arrow Keys | `down`, `left`, `right`, `up`, `pagedown`, `pageup`, `pgdn`, `pgup`, `end`, `home`, `plus`, `app`, `menu` |
| Action Keys | `tab`, `enter`, `esc`, `escape`, `space`, `backspace`, `delete`, `insert` |
| Numpad Keys | `numpad_0-numpad_9`, `numpad0-numpad9`, `numpad_add`, `numpad_plus`, `numpad_decimal`, `numpad_period`, `numpad_divide`, `numpad_minus`, `numpad_subtract`, `numpad_multiply` |
## Background Images and Icons
Some Terminal settings allow you to specify custom background images and icons. It is recommended that custom images and icons are stored in system-provided folders and are referred to using the correct [URI Schemes](https://docs.microsoft.com/en-us/windows/uwp/app-resources/uri-schemes). URI Schemes provide a way to reference files independent of their physical paths (which may change in the future).
The most useful URI schemes to remember when customizing background images and icons are:
| URI Scheme | Corresponding Physical Path | Use / description |
| --- | --- | ---|
| `ms-appdata:///Local/` | `%localappdata%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\` | Per-machine files |
| `ms-appdata:///Roaming/` | `%localappdata%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\RoamingState\` | Common files |
> ⚠ Note: Do not rely on file references using the `ms-appx` URI Scheme (i.e. icons). These files are considered an internal implementation detail and may change name/location or may be omitted in the future.
### Icons
Terminal displays icons for each of your profiles which Terminal generates for any built-in shells - PowerShell Core, PowerShell, and any installed Linux/WSL distros. Each profile refers to a stock icon via the `ms-appx` URI Scheme.
> ⚠ Note: Do not rely on the files referenced by the `ms-appx` URI Scheme - they are considered an internal implementation detail and may change name/location or may be omitted in the future.
You can refer to you own icons if you wish, e.g.:
```json
"icon" : "C:\\Users\\richturn\\OneDrive\\WindowsTerminal\\icon-ubuntu-32.png",
```
> 👉 Tip: Icons should be sized to 32x32px in an appropriate raster image format (e.g. .PNG, .GIF, or .ICO) to avoid having to scale your icons during runtime (causing a noticeable delay and loss of quality.)
### Custom Background Images
You can apply a background image to each of your profiles, allowing you to configure/brand/style each of your profiles independently from one another if you wish.
To do so, specify your preferred `backgroundImage`, position it using `backgroundImageAlignment`, set its opacity with `backgroundImageOpacity`, and/or specify how your image fill the available space using `backgroundImageStretchMode`.
For example:
```json
"backgroundImage": "C:\\Users\\richturn\\OneDrive\\WindowsTerminal\\bg-ubuntu-256.png",
"backgroundImageAlignment": "bottomRight",
"backgroundImageOpacity": 0.1,
"backgroundImageStretchMode": "none"
```
> 👉 Tip: You can easily roam your collection of images and icons across all your machines by storing your icons and images in OneDrive (as shown above).
With these settings, your Terminal's Ubuntu profile would look similar to this:
![Custom icon and background image](../images/custom-icon-and-background-image.jpg)
⚠ This document has moved to [the Customize Settings section of the Windows Terminal documentation](https://docs.microsoft.com/windows/terminal/customize-settings/global-settings).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

View file

@ -1,13 +1,7 @@
# Adding profiles for third-party tools
This doc will hopefully provide a useful guide for adding profiles for common
third-party tools to your
[settings.json](https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md)
file.
All of these profiles are provided _without_ their `guid` set. If you'd like to
set any of these profiles as your _default_ profile, you'll need to make sure to
[generate a unique guid](https://www.guidgenerator.com/) for them manually.
This doc will hopefully provide a useful guide for adding profiles for common third-party tools to your
[settings.json](https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-settings) file.
## Anaconda
@ -15,10 +9,10 @@ Assuming that you've installed Anaconda into `%USERPROFILE%\Anaconda3`:
```json
{
"commandline" : "cmd.exe /k \"%USERPROFILE%\\Anaconda3\\Scripts\\activate.bat %USERPROFILE%\\Anaconda3\"",
"icon" : "%USERPROFILE%/Anaconda3/Menu/anaconda-navigator.ico",
"name" : "Anaconda3",
"startingDirectory" : "%USERPROFILE%"
"commandline": "cmd.exe /k \"%USERPROFILE%\\Anaconda3\\Scripts\\activate.bat %USERPROFILE%\\Anaconda3\"",
"icon": "%USERPROFILE%\\Anaconda3\\Menu\\anaconda-navigator.ico",
"name": "Anaconda3",
"startingDirectory": "%USERPROFILE%"
}
```
@ -28,23 +22,23 @@ Assuming that you've installed cmder into `%CMDER_ROOT%`:
```json
{
"commandline" : "cmd.exe /k \"%CMDER_ROOT%\\vendor\\init.bat\"",
"name" : "cmder",
"icon" : "%CMDER_ROOT%/icons/cmder.ico",
"startingDirectory" : "%USERPROFILE%"
"commandline": "cmd.exe /k \"%CMDER_ROOT%\\vendor\\init.bat\"",
"name": "cmder",
"icon": "%CMDER_ROOT%\\icons\\cmder.ico",
"startingDirectory": "%USERPROFILE%"
}
```
## Cygwin
Assuming that you've installed Cygwin into `C:/Cygwin`:
Assuming that you've installed Cygwin into `C:\Cygwin`:
```json
{
"name" : "Cygwin",
"commandline" : "C:/Cygwin/bin/bash --login -i",
"icon" : "C:/Cygwin/Cygwin.ico",
"startingDirectory" : "C:/Cygwin/bin"
"name": "Cygwin",
"commandline": "C:\\Cygwin\\bin\\bash --login -i",
"icon": "C:\\Cygwin\\Cygwin.ico",
"startingDirectory": "C:\\Cygwin\\bin"
}
```
@ -58,49 +52,49 @@ Assuming that you've installed Far into `c:\Program Files\Far Manager`:
```json
{
"name" : "Far",
"commandline" : "\"c:\\program files\\far manager\\far.exe\"",
"startingDirectory" : "%USERPROFILE%",
"useAcrylic" : false
"name": "Far",
"commandline": "\"c:\\program files\\far manager\\far.exe\"",
"startingDirectory": "%USERPROFILE%",
"useAcrylic": false
},
```
## Git Bash
Assuming that you've installed Git Bash into `C:/Program Files/Git`:
Assuming that you've installed Git Bash into `C:\\Program Files\\Git`:
```json
{
"name" : "Git Bash",
"commandline" : "C:/Program Files/Git/bin/bash.exe -li",
"icon" : "C:/Program Files/Git/mingw64/share/git/git-for-windows.ico",
"startingDirectory" : "%USERPROFILE%"
"name": "Git Bash",
"commandline": "C:\\Program Files\\Git\\bin\\bash.exe -li",
"icon": "C:\\Program Files\\Git\\mingw64\\share\\git\\git-for-windows.ico",
"startingDirectory": "%USERPROFILE%"
}
````
## Git Bash (WOW64)
Assuming that you've installed Git Bash into `C:/Program Files (x86)/Git`:
Assuming that you've installed Git Bash into `C:\\Program Files (x86)\\Git`:
```json
{
"name" : "Git Bash",
"commandline" : "%ProgramFiles(x86)%/Git/bin/bash.exe -li",
"icon" : "%ProgramFiles(x86)%/Git/mingw32/share/git/git-for-windows.ico",
"startingDirectory" : "%USERPROFILE%"
"name": "Git Bash",
"commandline": "%ProgramFiles(x86)%\\Git\\bin\\bash.exe -li",
"icon": "%ProgramFiles(x86)%\\Git\\mingw32\\share\\git\\git-for-windows.ico",
"startingDirectory": "%USERPROFILE%"
}
```
## MSYS2
Assuming that you've installed MSYS2 into `C:/msys64`:
Assuming that you've installed MSYS2 into `C:\\msys64`:
```json
{
"name" : "MSYS2",
"commandline" : "C:/msys64/msys2_shell.cmd -defterm -no-start -mingw64",
"icon": "C:/msys64/msys2.ico",
"startingDirectory" : "C:/msys64/home/user"
"name": "MSYS2",
"commandline": "C:\\msys64\\msys2_shell.cmd -defterm -no-start -mingw64",
"icon": "C:\\msys64\\msys2.ico",
"startingDirectory": "C:\\msys64\\home\\user"
}
````
@ -110,9 +104,9 @@ Assuming that you've installed VS 2019 Professional:
```json
{
"name" : "Developer Command Prompt for VS 2019",
"commandline" : "cmd.exe /k \"C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/Tools/VsDevCmd.bat\"",
"startingDirectory" : "%USERPROFILE%"
"name": "Developer Command Prompt for VS 2019",
"commandline": "cmd.exe /k \"C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/Tools/VsDevCmd.bat\"",
"startingDirectory": "%USERPROFILE%"
}
```

View file

@ -1,201 +1 @@
---
author: Mike Griese @zadjii-msft
created on: 2020-01-16
last updated: 2020-01-17
---
# Using the `wt.exe` Commandline
As of [#4023], the Windows Terminal now supports accepting arguments on the
commandline, to enable launching the Terminal in a non-default configuration.
This document serves as a reference for all the parameters you can currently
pass, and gives some examples of how to use the `wt` commandline.
> NOTE: If you're running the Terminal built straight from the repo, you'll need
> to use `wtd.exe` and `wtd` instead of `wt.exe` and `wt`.
1. [Commandline Reference](#Reference)
1. [Commandline Examples](#Examples)
## Reference
### Options
#### `--help,-h,-?,/?,`
Display the help message.
## Subcommands
#### `new-tab`
`new-tab [terminal_parameters]`
Opens a new tab with the given customizations. On its _first_ invocation, also
opens a new window. Subsequent `new-tab` commands will all open new tabs in the
same window. <sup>[[1](#footnote-1)]</sup>
**Parameters**:
* `[terminal_parameters]`: See [[terminal_parameters]](#terminal_parameters).
#### `split-pane`
`split-pane [-H,--horizontal|-V,--vertical] [terminal_parameters]`
Creates a new pane in the currently focused tab by splitting the given pane
vertically or horizontally. <sup>[[1](#footnote-1)]</sup>
**Parameters**:
* `-H,--horizontal`, `-V,--vertical`: Used to indicate which direction to split
the pane. `-V` is "vertically" (think `[|]`), and `-H` is "horizontally"
(think `[-]`). If omitted, defaults to "auto", which splits the current pane
in whatever the larger dimension is. If both `-H` and `-V` are provided,
defaults to vertical.
* `[terminal_parameters]`: See [[terminal_parameters]](#terminal_parameters).
#### `focus-tab`
`focus-tab [--target,-t tab-index]|[--next,-n]|[--previous,-p]`
Moves focus to a given tab.
**Parameters**:
* `--target,-t tab-index`: moves focus to the tab at index `tab-index`. If
omitted, defaults to `0` (the first tab). Will display an error if combined
with either of `--next` or `--previous`.
* `-n,--next`: Move focus to the next tab. Will display an error if combined
with either of `--previous` or `--target`.
* `-p,--previous`: Move focus to the previous tab. Will display an error if
combined with either of `--next` or `--target`.
#### `[terminal_parameters]`
Some of the preceding commands are used to create a new terminal instance.
These commands are listed above as accepting `[terminal_parameters]` as a
parameter. For these commands, `[terminal_parameters]` can be any of the
following:
`[--profile,-p profile-name] [--startingDirectory,-d starting-directory] [commandline]`
* `--profile,-p profile-name`: Use the given profile to open the new tab/pane,
where `profile-name` is the `name` or `guid` of a profile. If `profile-name`
does not match _any_ profiles, uses the default.
* `--startingDirectory,-d starting-directory`: Overrides the value of
`startingDirectory` of the specified profile, to start in `starting-directory`
instead.
* `commandline`: A commandline to replace the default commandline of the
selected profile. If the user wants to use a `;` in this commandline, it
should be escaped as `\;`.
### Notes
* <span id="footnote-1"></span> [1]: If you try to run a `wt` commandline while running in a Windows Terminal window, the commandline will _always_ create a new window by default. Being able to run `wt` commandlines in the _current_ window is planned in the future - for more information, refer to [#4472].
## Examples
### Open Windows Terminal in the current directory
```powershell
wt -d .
```
This will launch a new Windows Terminal window in the current working directory.
It will use your default profile, but instead of using the `startingDirectory`
property from that it will use the current path. This is especially useful for
launching the Windows Terminal in a directory you currently have open in an
`explorer.exe` window.
### Opening with multiple panes
If you want to open with multiple panes in the same tab all at once, you can use
the `split-pane` command to create new panes.
Consider the following commandline:
```powershell
wt ; split-pane -p "Windows PowerShell" ; split-pane -H wsl.exe
```
This creates a new Windows Terminal window with one tab, and 3 panes:
* `wt`: Creates the new tab with the default profile
* `split-pane -p "Windows PowerShell"`: This will create a new pane, split from
the parent with the default profile. This pane will open with the "Windows
PowerShell" profile
* `split-pane -H wsl.exe`: This will create a third pane, split _horizontally_
from the "Windows PowerShell" pane. It will be running the default profile,
and will use `wsl.exe` as the commandline (instead of the default profile's
`commandline`).
### Using multiple commands from PowerShell
The Windows Terminal uses the semicolon character `;` as a delimiter for
separating subcommands in the `wt` commandline. Unfortunately, `powershell` also
uses `;` as a command separator. To work around this you can use the following
tricks to help run multiple wt sub commands from powershell. In all the
following examples, we'll be creating a new Terminal window with three panes -
one running `cmd`, one with `powershell`, and a last one running `wsl`.
In each of the following examples, we're using the `Start-Process` command to
run `wt`. For more information on why we're using `Start-Process`, see ["Using
`start`"](#using-start) below.
#### Single quoted parameters (if you aren't calculating anything):
In this example, we'll wrap all the parameters to `wt` in single quotes (`'`)
```PowerShell
start wt 'new-tab "cmd"; split-pane -p "Windows PowerShell" ; split-pane -H wsl.exe'
```
#### Escaped quotes (if you need variables):
If you'd like to pass a value contained in a variable to the `wt` commandline,
instead use the following syntax:
```PowerShell
$ThirdPane = "wsl.exe"
start wt "new-tab cmd; split-pane -p `"Windows PowerShell`" ; split-pane -H $ThirdPane"
```
Note the usage of `` ` `` to escape the double-quotes (`"`) around "Windows
Powershell" in the `-p` parameter to the `split-pane` sub-command.
#### Using `start`
All the above examples explicitly used `start` to launch the Terminal.
In the following examples, we're going to not use `start` to run the
commandline. Instead, we'll try two other methods of escaping the commandline:
* Only escaping the semicolons so that `powershell` will ignore them and pass
them straight to `wt`.
* Using `--%`, so powershell will treat the rest of the commandline as arguments
to the application.
```PowerShell
wt new-tab "cmd" `; split-pane -p "Windows PowerShell" `; split-pane -H wsl.exe
```
```Powershell
wt --% new-tab cmd ; split-pane -p "Windows PowerShell" ; split-pane -H wsl.exe
```
In both these examples, the newly created Windows Terminal window will create
the window by correctly parsing all the provided commandline arguments.
However, these methods are _not_ recommended currently, as Powershell will wait
for the newly-created Terminal window to be closed before returning control to
Powershell. By default, Powershell will always wait for Windows Store
applications (like the Windows Terminal) to close before returning to the
prompt. Note that this is different than the behavior of `cmd`, which will return
to the prompt immediately. See
[Powershell/PowerShell#9970](https://github.com/PowerShell/PowerShell/issues/9970)
for more details on this bug.
[#4023]: https://github.com/microsoft/terminal/pull/4023
[#4472]: https://github.com/microsoft/terminal/issues/4472
⚠ This document has moved to [Using command-line arguments for Windows Terminal](https://docs.microsoft.com/windows/terminal/command-line-arguments).

View file

@ -1,483 +1 @@
# Editing Windows Terminal JSON Settings
One way (currently the only way) to configure Windows Terminal is by editing the
`settings.json` settings file. At the time of writing you can open the settings
file in your default editor by selecting `Settings` from the WT pull down menu.
The settings are stored in the file `$env:LocalAppData\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json`.
As of [#2515](https://github.com/microsoft/terminal/pull/2515), the settings are
split into _two_ files: a hardcoded `defaults.json`, and `settings.json`, which
contains the user settings. Users should only be concerned with the contents of
the `settings.json`, which contains their customizations. The `defaults.json`
file is only provided as a reference of what the default settings are. For more
details on how these two files work, see [Settings
Layering](#settings-layering). To view the default settings file, click on the
"Settings" button while holding the <kbd>Alt</kbd> key.
Details of specific settings can be found [here](../cascadia/SettingsSchema.md).
A general introduction is provided below.
The settings are grouped under four headings:
1. Global: Settings that apply to the whole application e.g. Default profile, initial size etc.
2. Key Bindings: Actually a sub field of the global settings, but worth discussing separately
3. Profiles: A group of settings to be applied to a tab when it is opened using that profile. E.g. shell to use, cursor shape etc.
4. Schemes: Sets of colors for background, text etc. that can be used by profiles
## Global Settings
These settings define startup defaults, and application-wide settings that might
not affect a particular terminal instance.
* Theme
* Title Bar options
* Initial size
* Default profile used when the Windows Terminal is started
Example settings include
```json
{
"defaultProfile" : "{58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530}",
"initialCols" : 120,
"initialRows" : 50,
"theme" : "system",
"keybindings" : []
...
}
```
These global properties should exist in the root json object.
## Key Bindings
This is an array of key chords and shortcuts to invoke various commands.
Each command can have more than one key binding.
> 👉 **Note**: Key bindings is a subfield of the global settings and
> key bindings apply to all profiles in the same manner.
For example, here's a sample of the default keybindings:
```json
{
"keybindings":
[
{ "command": "closePane", "keys": ["ctrl+shift+w"] },
{ "command": "copy", "keys": ["ctrl+shift+c"] },
{ "command": "newTab", "keys": ["ctrl+shift+t"] },
// etc.
]
}
```
You can also use a single key chord string as the value of `"keys"`.
It will be treated as a chord of length one.
This will allow you to simplify the above snippet as follows:
```json
{
"keybindings":
[
{ "command": "closePane", "keys": "ctrl+shift+w" },
{ "command": "copy", "keys": "ctrl+shift+c" },
{ "command": "newTab", "keys": "ctrl+shift+t" },
// etc.
]
}
```
A list of default key bindings is available [here](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/defaults.json#L204).
### Unbinding keys
If you ever come across a key binding that you're unhappy with, it's possible to
easily change the keybindings. For example, vim uses <kbd>Ctrl+^</kbd> as a
binding for "switch to previous buffer", which conflicts with the Terminal's
default keybinding for "open a new tab with the sixth profile". If you'd like to
unbind that keybinding, and allow the keystroke to fall through to vim, you can
add the following to your keybindings:
```json
{
"command" : null, "keys" : ["ctrl+shift+6"]
},
```
This will _unbind_ <kbd>Ctrl+Shift+6</kbd>, allowing vim to use the keystroke
instead of the terminal.
### Binding multiple keys
You can have multiple key chords bound to the same action. To do this, simply
add multiple bindings for the same action. For example:
```json
"keybindings" :
[
{ "command": "copy", "keys": "ctrl+shift+c" },
{ "command": "copy", "keys": "ctrl+c" },
{ "command": "copy", "keys": "enter" }
]
```
In this snippet, all three of <kbd>ctrl+shift+c</kbd>, <kbd>ctrl+c</kbd> and <kbd>enter</kbd> are bound to `copy`.
## Profiles
A profile contains the settings applied when a new WT tab is opened. Each
profile is identified by a GUID and contains a number of other fields.
> 👉 **Note**: The `guid` property is the unique identifier for a profile. If
> multiple profiles all have the same `guid` value, you may see unexpected
> behavior.
* Which command to execute on startup - this can include arguments.
* Starting directory
* Which color scheme to use (see Schemes below)
* Font face and size
* Various settings to control appearance. E.g. Opacity, icon, cursor appearance, display name etc.
* Other behavioral settings. E.g. Close on exit, snap on input, .....
Example settings include
```json
"closeOnExit" : true,
"colorScheme" : "Campbell",
"commandline" : "wsl.exe -d Debian",
"cursorColor" : "#FFFFFF",
"cursorShape" : "bar",
"fontFace" : "Hack",
"fontSize" : 9,
"guid" : "{58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530}",
"name" : "Debian",
"startingDirectory" : "%USERPROFILE%\\wslhome"
....
```
> 👉 **Note**: To use backslashes in any path field, you'll need to escape them following JSON escaping rules (like shown above). As an alternative, you can use forward slashes ("%USERPROFILE%/wslhome").
The profile GUID is used to reference the default profile in the global settings.
The values for background image stretch mode are documented [here](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.stretch).
### Hiding a profile
If you want to remove a profile from the list of profiles in the new tab
dropdown, but keep the profile around in your `settings.json` file, you can add
the property `"hidden": true` to the profile's json. This can also be used to
remove the default `cmd` and PowerShell profiles, if the user does not wish to
see them.
## Color Schemes
Each scheme defines the color values to be used for various terminal escape sequences.
Each schema is identified by the name field. Examples include
```json
"name" : "Campbell",
"background" : "#0C0C0C",
"black" : "#0C0C0C",
"blue" : "#0037DA",
"foreground" : "#F2F2F2",
"green" : "#13A10E",
"red" : "#C50F1F",
"white" : "#CCCCCC",
"yellow" : "#C19C00"
...
```
The schema name can then be referenced in one or more profiles.
## Settings layering
The runtime settings are actually constructed from _three_ sources:
* The default settings, which are hardcoded into the application, and available
in `defaults.json`. This includes the default keybindings, color schemes, and
profiles for both Windows PowerShell and Command Prompt (`cmd.exe`).
* Dynamic Profiles, which are generated at runtime. These include Powershell
Core, the Azure Cloud Shell connector, and profiles for and WSL distros.
* The user settings from `settings.json`.
Settings from each of these sources are "layered" upon the settings from
previous sources. In this manner, the user settings in `settings.json` can
contain _only the changes from the default settings_. For example, if a user
would like to only change the color scheme of the default `cmd` profile to
"Solarized Dark", you could change your cmd profile to the following:
```js
{
// Make changes here to the cmd.exe profile
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"colorScheme": "Solarized Dark"
}
```
Here, we know we're changing the `cmd` profile, because the `guid`
`"{0caa0dad-35be-5f56-a8ff-afceeeaa6101}"` is `cmd`'s unique GUID. Any profiles
with that GUID will all be treated as the same object. Any changes in that
profile will overwrite those from the defaults.
Similarly, you can overwrite settings from a color scheme by defining a color
scheme in `settings.json` with the same name as a default color scheme.
If you'd like to unbind a keystroke that's bound to an action in the default
keybindings, you can set the `"command"` to `"unbound"` or `null`. This will
allow the keystroke to fallthrough to the commandline application instead of
performing the default action.
### Dynamic Profiles
When dynamic profiles are created at runtime, they'll be added to the
`settings.json` file. You can identify these profiles by the presence of a
`"source"` property. These profiles are tied to their source - if you uninstall
a linux distro, then the profile will remain in your `settings.json` file, but
the profile will be hidden.
The Windows Terminal uses the `guid` property of these dynamically-generated
profiles to uniquely identify them. If you try to change the `guid` of a
dynamically-generated profile, the Terminal will automatically recreate a new
entry for that profile.
If you'd like to disable a particular dynamic profile source, you can add that
`source` to the global `"disabledProfileSources"` array. For example, if you'd
like to hide all the WSL profiles, you could add the following setting:
```json
"disabledProfileSources": ["Windows.Terminal.WSL"],
...
```
> 👉 **NOTE**: On launch, if a dynamic profile generator is enabled, it will
> always add new profiles it detects to your list of profiles. If you delete a
> dynamically generated profile from your list of profiles, it will just get
> re-added the next time the Terminal is launched! To remove a dynamic profile
> from your list of profiles, make sure to set `"hidden": true` in the profile.
### Default settings
In [#2325](https://github.com/microsoft/terminal/issues/2325), we introduced the
concept of "Default Profile Settings". These are settings that will apply to all
of your profiles by default. Profiles can still override these settings
individually. With default profile settings, you can easily make changes to all
your profiles at once. For example, given the following settings:
```json
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"profiles":
[
{
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"fontFace": "Cascadia Code",
"fontSize": 14
},
{
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "cmd",
"commandline": "cmd.exe",
"fontFace": "Cascadia Code",
"fontSize": 14
},
{
"commandline" : "cmd.exe /k %CMDER_ROOT%\\vendor\\init.bat",
"name" : "cmder",
"startingDirectory" : "%USERPROFILE%",
"fontFace": "Cascadia Code",
"fontSize": 14
}
],
```
All three of these profiles are using "Cascadia Code" as their `"fontFace"`, and
14 as their `fontSize`. With default profile settings, you can easily set these
properties for all your profiles, like so:
```json
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"profiles": {
"defaults":
{
"fontFace": "Cascadia Code",
"fontSize": 14
},
"list": [
{
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe"
},
{
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "cmd",
"commandline": "cmd.exe"
},
{
"commandline" : "cmd.exe /k %CMDER_ROOT%\\vendor\\init.bat",
"name" : "cmder",
"startingDirectory" : "%USERPROFILE%"
}
]
},
```
Note that the `profiles` property has changed in this example from a _list_ of
profiles, to an _object_ with two properties:
* a `list` that contains the list of all the profiles
* the new `defaults` object, which contains all the settings that should apply to
every profile.
What if I wanted a profile to have a different value for a property other than
the default? Simply set the property in the profile's entry to override the
value from `defaults`. Let's say you want the `cmd` profile to have _"Consolas"_
as the font, but the rest of your profiles to still have _"Cascadia Code"_. You
could achieve that with the following:
```json
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"profiles": {
"defaults":
{
"fontFace": "Cascadia Code",
"fontSize": 14
},
"list": [
{
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe"
},
{
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "cmd",
"commandline": "cmd.exe",
"fontFace": "Consolas"
},
{
"commandline" : "cmd.exe /k %CMDER_ROOT%\\vendor\\init.bat",
"name" : "cmder",
"startingDirectory" : "%USERPROFILE%"
}
]
},
```
In the above settings, the `"fontFace"` in the `cmd.exe` profile overrides the
`"fontFace"` from the `defaults`.
## Configuration Examples
### Add a custom background to the WSL Debian terminal profile
1. Download the [Debian JPG logo](https://www.debian.org/logos/openlogo-100.jpg)
2. Put the image in the
`$env:LocalAppData\Packages\Microsoft.WindowsTerminal_<randomString>\LocalState\`
directory (same directory as your `settings.json` file).
__NOTE__: You can put the image anywhere you like, the above suggestion happens to be convenient.
3. Open your WT json properties file.
4. Under the Debian Linux profile, add the following fields:
```json
"backgroundImage": "ms-appdata:///Local/openlogo-100.jpg",
"backgroundImageOpacity": 1,
"backgroundImageStretchMode" : "none",
"backgroundImageAlignment" : "topRight",
```
5. Make sure that `useAcrylic` is `false`.
6. Save the file.
7. Jump over to WT and verify your changes.
Notes:
1. You will need to experiment with different color settings
and schemes to make your terminal text visible on top of your image
2. If you store the image in the UWP directory (the same directory as your settings.json file),
then you should use the URI style path name given in the above example.
More information about UWP URI schemes [here](https://docs.microsoft.com/en-us/windows/uwp/app-resources/uri-schemes).
3. Instead of using a UWP URI you can use a:
1. URL such as
`http://open.esa.int/files/2017/03/Mayer_and_Bond_craters_seen_by_SMART-1-350x346.jpg`
2. Local file location such as `C:\Users\Public\Pictures\openlogo.jpg`
### Adding Copy and Paste Keybindings
As of [#1093](https://github.com/microsoft/terminal/pull/1093) (first available
in Windows Terminal v0.3), the Windows Terminal now supports copy and paste
keyboard shortcuts. However, if you installed and ran the terminal before that,
you won't automatically get the new keybindings added to your settings. If you'd
like to add shortcuts for copy and paste, you can do so by inserting the
following objects into your `globals.keybindings` array:
```json
{ "command": "copy", "keys": ["ctrl+shift+c"] },
{ "command": "paste", "keys": ["ctrl+shift+v"] }
```
> 👉 **Note**: you can also add a keybinding for the `copy` command with the argument `"trimWhitespace": true`. This removes newlines as the text is copied to your clipboard.
This will add copy and paste on <kbd>ctrl+shift+c</kbd>
and <kbd>ctrl+shift+v</kbd> respectively.
You can set the keybindings to whatever you'd like. If you prefer
<kbd>ctrl+c</kbd> to copy, then set the `keys` to `"ctrl+c"`.
You can even set multiple keybindings for a single action if you'd like. For example:
```json
{
"command" : "paste",
"keys" :
[
"ctrl+shift+v"
]
},
{
"command" : "paste",
"keys" :
[
"shift+insert"
]
}
```
will bind both <kbd>ctrl+shift+v</kbd> and
<kbd>shift+Insert</kbd> to `paste`.
> 👉 **Note**: If you set your copy keybinding to `"ctrl+c"`, you'll only be able to send
an interrupt to the commandline application using <kbd>Ctrl+C</kbd> when there's
no text selection. Additionally, if you set `paste` to `"ctrl+v"`, commandline
applications won't be able to read a ctrl+v from the input. For these reasons,
we suggest `"ctrl+shift+c"` and `"ctrl+shift+v"`
### Setting the `startingDirectory` of WSL Profiles to `~`
By default, the `startingDirectory` of a profile is `%USERPROFILE%`
(`C:\Users\<YourUsername>`). This is a Windows path. However, for WSL, you might
want to use the WSL home path instead. At the time of writing (26decf1 / Nov.
1st, 2019), `startingDirectory` only accepts a Windows-style path, so setting it
to start within the WSL distro can be a little tricky.
Fortunately, with Windows 1903, the filesystems of WSL distros can easily be
addressed using the `\\wsl$\` prefix. For any WSL distro whose name is
`DistroName`, you can use `\\wsl$\DistroName` as a Windows path that points to
the root of that distro's filesystem.
For example, the following works as a profile to launch the "Ubuntu-18.04"
distro in it's home path:
```json
{
"name": "Ubuntu-18.04",
"commandline" : "wsl -d Ubuntu-18.04",
"startingDirectory" : "//wsl$/Ubuntu-18.04/home/<Your Ubuntu Username>",
}
```
⚠ This document has moved to [the Customize Settings section of the Windows Terminal documentation](https://docs.microsoft.com/windows/terminal/customize-settings/global-settings).

View file

@ -1,91 +1 @@
# Windows Terminal User Documentation
NOTE: At the time of writing Windows Terminal is still under active development and many things will
change. If you notice an error in the docs, please raise an issue. Or better yet, please file a PR with an appropriate update!
## Installing Windows Terminal
### From Source Code
To compile Windows Terminal yourself using the source code, follow the instructions in the [README](/README.md#developer-guidance).
### From the Microsoft Store
1. Make sure you have upgraded to the current Windows 10 release (at least build `1903`). To determine your build number, see [winver](https://docs.microsoft.com/en-us/windows/client-management/windows-version-search).
2. Open the Windows Terminal listing in the [Microsoft Store](https://aka.ms/install-terminal).
3. Review the minimum system requirements to confirm you can successfully install Windows Terminal.
4. Click `Get` to begin the installation process.
## Starting Windows Terminal
1. Locate the _Windows Terminal_ app in your Start menu.
2. Click _Windows Terminal_ to launch the app. If you need administrative privileges, right-click the entry and click `Run as administrator`. Alternatively, you can highlight the app and press `Ctrl`+`Shift`+`Enter`.
NOTE: The default shell is PowerShell; you can change this using the _Running a Different Shell_ procedure.
### Command line options
Windows Terminal has implemented a rich set of command-line options in part as response to issue [#607](https://github.com/microsoft/terminal/issues/607). See [UsingCommandlineArguments.md](https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingCommandlineArguments.md) for details.
## Multiple Tabs
Additional shells can be started by hitting the `+` button from the tab bar -- a new instance of the
default shell is displayed (default shortcut: <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>1</kbd>).
## Running a Different Shell
Note: This section assumes you already have _Windows Subsystem for Linux_ (WSL) installed. For more information, see [the installation guide](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
Windows Terminal uses PowerShell as its default shell. You can also use Windows Terminal to launch other shells, such as `cmd.exe` or WSL's `bash`:
1. In the tab bar, click the `⌵` button to view the available shells.
2. Choose your shell from the dropdown list. The new shell session will open in a new tab.
To customize the shell list, see the _Configuring Windows Terminal_ section below.
## Starting a new PowerShell tab with admin privilege
There is no current plan to support this feature for security reasons. See issue [#632](https://github.com/microsoft/terminal/issues/632)
## Selecting and Copying Text in Windows Terminal
As in ConHost, a selection can be made by left-clicking and dragging the mouse across the terminal. This is a line selection by default, meaning that the selection will wrap to the end of the line and the beginning of the next one. You can select in block mode by holding down the <kbd>Alt</kbd> key when starting a selection.
To copy the text to your clipboard, you can right-click the terminal when a selection is active. As of [#1224](https://github.com/microsoft/terminal/pull/1224) (first available in Windows Terminal v0.4), the Windows Terminal now supports HTML copy. The HTML is automatically copied to your clipboard along with the regular text in any copy operation.
If there is not an active selection, a right-click will paste the text content from your clipboard to the terminal.
Copy and paste operations can also be keybound. For more information on how to bind keys, see [Using Json Settings](UsingJsonSettings.md#adding-copy-and-paste-keybindings).
> 👉 **Note**: If you have the `copyOnSelect` global setting enabled, a selection will persist and immediately copy the selected text to your clipboard. Right-clicking will always paste your clipboard data.
## Add a "Open Windows Terminal Here" to File Explorer
Not currently supported "out of the box" (See issue [#1060](https://github.com/microsoft/terminal/issues/1060)). However, you can open Windows Terminal in current directory by typing `wt -d .` in the Explorer address bar.
## Configuring Windows Terminal
All Windows Terminal settings are currently managed using the `settings.json` file, located within `$env:LocalAppData\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState`.
To open the settings file from Windows Terminal:
1. Click the `⌵` button in the top bar.
2. From the dropdown list, click `Settings`. You can also use a shortcut: <kbd>Ctrl</kbd>+<kbd>,</kbd>.
3. Your default `json` editor will open the settings file.
For an introduction to the various settings, see [Using Json Settings](UsingJsonSettings.md). The list of valid settings can be found in the [settings.json documentation](../cascadia/SettingsSchema.md) section.
## Tips and Tricks
1. In PowerShell you can discover if the Windows Terminal is being used by checking for the existence of the environment variable `WT_SESSION`.
Under pwsh you can also use
`(Get-Process -Id $pid).Parent.ProcessName -eq 'WindowsTerminal'`
(ref [https://twitter.com/r_keith_hill/status/1142871145852440576](https://twitter.com/r_keith_hill/status/1142871145852440576))
2. Terminal zoom can be changed by holding <kbd>Ctrl</kbd> and scrolling with mouse.
3. Background opacity can be changed by holding <kbd>Ctrl</kbd>+<kbd>Shift</kbd> and scrolling with mouse. Note that acrylic transparency is limited by the OS only to focused windows.
4. Open Windows Terminal in current directory by typing `wt -d .` in the address bar.
5. Pin the Windows Terminal to the taskbar. Now it can be launched using the Windows shortcut <kbd>Win</kbd>+<kbd>Number</kbd> (e.g. <kbd>Win</kbd>+<kbd>1</kbd> or any other number based on the position in the taskbar!). Press <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>Number</kbd> to always launch a new window.
6. Please add more Tips and Tricks.
⚠ Our user-facing documentation has moved to the [Windows Terminal documentation page](https://docs.microsoft.com/windows/terminal/).

Binary file not shown.

Binary file not shown.

View file

@ -17,5 +17,5 @@ Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadi
### Fonts Included
* Cascadia Code, Cascadia Mono (2008.25)
* from microsoft/cascadia-code@678eea921b0c8b921b9fb009bb16d3d2ca5b8112
* Cascadia Code, Cascadia Mono (2009.14)
* from microsoft/cascadia-code@716c6e6f24ce8e23e28936db9a106a6129ca9931

View file

@ -131,11 +131,11 @@ namespace TerminalAppLocalTests
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
auto scheme0 = ColorScheme::FromJson(scheme0Json);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_schemeName);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_selectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_cursorColor);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_Name);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 1), scheme0->_table[XTERM_BLUE_ATTR]);
@ -144,10 +144,10 @@ namespace TerminalAppLocalTests
L"Layering scheme1 on top of scheme0"));
scheme0->LayerJson(scheme1Json);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_selectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_cursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
@ -156,10 +156,10 @@ namespace TerminalAppLocalTests
L"Layering scheme2Json on top of (scheme0+scheme1)"));
scheme0->LayerJson(scheme2Json);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_selectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_cursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 3, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 3, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
@ -218,8 +218,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
}
settings->_LayerOrCreateColorScheme(scheme1Json);
@ -238,10 +238,10 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme2Json);
@ -259,10 +259,10 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme3Json);
@ -283,12 +283,12 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
}
}
}

View file

@ -20,6 +20,7 @@ static constexpr std::string_view ForegroundKey{ "foreground" };
static constexpr std::string_view BackgroundKey{ "background" };
static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" };
static constexpr std::string_view CursorColorKey{ "cursorColor" };
static constexpr std::array<std::string_view, 16> TableColors = {
"black",
"red",
@ -40,26 +41,19 @@ static constexpr std::array<std::string_view, 16> TableColors = {
};
ColorScheme::ColorScheme() :
_schemeName{ L"" },
_table{},
_defaultForeground{ DEFAULT_FOREGROUND_WITH_ALPHA },
_defaultBackground{ DEFAULT_BACKGROUND_WITH_ALPHA },
_selectionBackground{ DEFAULT_FOREGROUND },
_cursorColor{ DEFAULT_CURSOR_COLOR }
_Foreground{ DEFAULT_FOREGROUND_WITH_ALPHA },
_Background{ DEFAULT_BACKGROUND_WITH_ALPHA },
_SelectionBackground{ DEFAULT_FOREGROUND },
_CursorColor{ DEFAULT_CURSOR_COLOR }
{
}
ColorScheme::ColorScheme(winrt::hstring name, Color defaultFg, Color defaultBg, Color cursorColor) :
_schemeName{ name },
_table{},
_defaultForeground{ defaultFg },
_defaultBackground{ defaultBg },
_selectionBackground{ DEFAULT_FOREGROUND },
_cursorColor{ cursorColor }
{
}
ColorScheme::~ColorScheme()
_Name{ name },
_Foreground{ defaultFg },
_Background{ defaultBg },
_SelectionBackground{ DEFAULT_FOREGROUND },
_CursorColor{ cursorColor }
{
}
@ -89,7 +83,7 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
std::wstring nameFromJson{};
if (JsonUtils::GetValueForKey(json, NameKey, nameFromJson))
{
return nameFromJson == _schemeName;
return nameFromJson == _Name;
}
return false;
}
@ -106,50 +100,60 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
// <none>
void ColorScheme::LayerJson(const Json::Value& json)
{
JsonUtils::GetValueForKey(json, NameKey, _schemeName);
JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground);
JsonUtils::GetValueForKey(json, BackgroundKey, _defaultBackground);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _selectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _cursorColor);
JsonUtils::GetValueForKey(json, NameKey, _Name);
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
int i = 0;
for (const auto& current : TableColors)
for (unsigned int i = 0; i < TableColors.size(); ++i)
{
JsonUtils::GetValueForKey(json, current, _table.at(i));
i++;
JsonUtils::GetValueForKey(json, til::at(TableColors, i), _table.at(i));
}
}
winrt::hstring ColorScheme::Name() const noexcept
// Method Description:
// - Create a new serialized JsonObject from an instance of this class
// Arguments:
// - <none>
// Return Value:
// <none>
Json::Value ColorScheme::ToJson()
{
return _schemeName;
Json::Value json{ Json::ValueType::objectValue };
JsonUtils::SetValueForKey(json, NameKey, _Name);
JsonUtils::SetValueForKey(json, ForegroundKey, _Foreground);
JsonUtils::SetValueForKey(json, BackgroundKey, _Background);
JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor);
for (unsigned int i = 0; i < TableColors.size(); ++i)
{
JsonUtils::SetValueForKey(json, til::at(TableColors, i), _table.at(i));
}
return json;
}
winrt::com_array<Color> ColorScheme::Table() const noexcept
{
winrt::com_array<Color> result{ COLOR_TABLE_SIZE };
winrt::com_array<Color> result{ base::checked_cast<uint32_t>(_table.size()) };
std::transform(_table.begin(), _table.end(), result.begin(), [](til::color c) -> Color { return c; });
return result;
}
Color ColorScheme::Foreground() const noexcept
// Method Description:
// - Set a color in the color table
// Arguments:
// - index: the index of the desired color within the table
// - value: the color value we are setting the color table color to
// Return Value:
// - none
void ColorScheme::SetColorTableEntry(uint8_t index, const winrt::Windows::UI::Color& value) noexcept
{
return _defaultForeground;
}
Color ColorScheme::Background() const noexcept
{
return _defaultBackground;
}
Color ColorScheme::SelectionBackground() const noexcept
{
return _selectionBackground;
}
Color ColorScheme::CursorColor() const noexcept
{
return _cursorColor;
THROW_HR_IF(E_INVALIDARG, index > _table.size() - 1);
_table[index] = value;
}
// Method Description:

View file

@ -34,28 +34,26 @@ namespace winrt::TerminalApp::implementation
public:
ColorScheme();
ColorScheme(hstring name, Windows::UI::Color defaultFg, Windows::UI::Color defaultBg, Windows::UI::Color cursorColor);
~ColorScheme();
static com_ptr<ColorScheme> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json);
hstring Name() const noexcept;
com_array<Windows::UI::Color> Table() const noexcept;
Windows::UI::Color Foreground() const noexcept;
Windows::UI::Color Background() const noexcept;
Windows::UI::Color SelectionBackground() const noexcept;
Windows::UI::Color CursorColor() const noexcept;
Json::Value ToJson();
static std::optional<std::wstring> GetNameFromJson(const Json::Value& json);
com_array<Windows::UI::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const winrt::Windows::UI::Color& value) noexcept;
GETSET_PROPERTY(winrt::hstring, Name);
GETSET_COLORPROPERTY(Foreground); // defined in constructor
GETSET_COLORPROPERTY(Background); // defined in constructor
GETSET_COLORPROPERTY(SelectionBackground); // defined in constructor
GETSET_COLORPROPERTY(CursorColor); // defined in constructor
private:
hstring _schemeName;
std::array<til::color, COLOR_TABLE_SIZE> _table;
til::color _defaultForeground;
til::color _defaultBackground;
til::color _selectionBackground;
til::color _cursorColor;
friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::ColorSchemeTests;

View file

@ -5,15 +5,15 @@ namespace TerminalApp
{
[default_interface] runtimeclass ColorScheme {
ColorScheme();
ColorScheme(String name, Windows.UI.Color defaultFg, Windows.UI.Color defaultBg, Windows.UI.Color cursorColor);
String Name { get; };
String Name;
Windows.UI.Color Foreground { get; };
Windows.UI.Color Background { get; };
Windows.UI.Color SelectionBackground { get; };
Windows.UI.Color CursorColor { get; };
Windows.UI.Color Foreground;
Windows.UI.Color Background;
Windows.UI.Color SelectionBackground;
Windows.UI.Color CursorColor;
Windows.UI.Color[] Table { get; };
void SetColorTableEntry(UInt8 index, Windows.UI.Color value);
}
}

View file

@ -975,30 +975,17 @@ namespace winrt::TerminalApp::implementation
{
case CollectionChange::ItemChanged:
{
winrt::com_ptr<Command> item;
item.copy_from(winrt::get_self<Command>(_allTabActions.GetAt(idx)));
item->propertyChangedRevoker.revoke();
auto tab = tabList.GetAt(idx);
GenerateCommandForTab(idx, false, tab);
UpdateTabIndices(idx);
break;
}
case CollectionChange::ItemInserted:
{
auto tab = tabList.GetAt(idx);
GenerateCommandForTab(idx, true, tab);
UpdateTabIndices(idx);
_allTabActions.InsertAt(idx, tab.SwitchToTabCommand());
break;
}
case CollectionChange::ItemRemoved:
{
winrt::com_ptr<Command> item;
item.copy_from(winrt::get_self<Command>(_allTabActions.GetAt(idx)));
item->propertyChangedRevoker.revoke();
_allTabActions.RemoveAt(idx);
UpdateTabIndices(idx);
break;
}
}
@ -1007,83 +994,6 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - In the case where a tab is removed or reordered, the given indices of
// the tab switch commands following the removed/reordered tab will get out of sync by 1
// (e.g. if tab 1 is removed, tabs 2,3,4,... need to become tabs 1,2,3,...)
// This function just loops through the tabs following startIdx and adjusts their given indices.
// Arguments:
// - startIdx: The index to start the update loop at.
// Return Value:
// - <none>
void CommandPalette::UpdateTabIndices(const uint32_t startIdx)
{
for (auto i = startIdx; i < _allTabActions.Size(); ++i)
{
auto command = _allTabActions.GetAt(i);
command.Action().Args().as<implementation::SwitchToTabArgs>()->TabIndex(i);
}
}
// Method Description:
// - Create a tab switching command based on the given tab object and insert/update the command
// at the given index. The command will call a SwitchToTab action on the given idx.
// Arguments:
// - idx: The index to insert or update the tab switch command.
// - tab: The tab object to refer to when creating the tab switch command.
// Return Value:
// - <none>
void CommandPalette::GenerateCommandForTab(const uint32_t idx, bool inserted, TerminalApp::Tab& tab)
{
auto focusTabAction = winrt::make_self<implementation::ActionAndArgs>();
auto args = winrt::make_self<implementation::SwitchToTabArgs>();
args->TabIndex(idx);
focusTabAction->Action(ShortcutAction::SwitchToTab);
focusTabAction->Args(*args);
auto command = winrt::make_self<implementation::Command>();
command->Action(*focusTabAction);
command->Name(tab.Title());
command->IconSource(tab.IconSource());
// Listen for changes to the Tab so we can update this Command's attributes accordingly.
auto weakThis{ get_weak() };
auto weakCommand{ command->get_weak() };
command->propertyChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [weakThis, weakCommand, tab](auto&&, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args) {
auto palette{ weakThis.get() };
auto command{ weakCommand.get() };
if (palette && command)
{
if (args.PropertyName() == L"Title")
{
if (command->Name() != tab.Title())
{
command->Name(tab.Title());
}
}
if (args.PropertyName() == L"IconSource")
{
if (command->IconSource() != tab.IconSource())
{
command->IconSource(tab.IconSource());
}
}
}
});
if (inserted)
{
_allTabActions.InsertAt(idx, *command);
}
else
{
_allTabActions.SetAt(idx, *command);
}
}
void CommandPalette::EnableTabSwitcherMode(const bool searchMode, const uint32_t startIdx)
{
_switcherStartIdx = startIdx;

View file

@ -87,8 +87,6 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::TerminalControl::IKeyBindings _bindings;
// Tab Switcher
void GenerateCommandForTab(const uint32_t idx, bool inserted, winrt::TerminalApp::Tab& tab);
void UpdateTabIndices(const uint32_t startIdx);
Windows::Foundation::Collections::IVector<TerminalApp::Command> _allTabActions{ nullptr };
uint32_t _switcherStartIdx;
void _anchorKeyUpHandler();

View file

@ -103,6 +103,8 @@ namespace TerminalApp::JsonUtils
T FromJson(const Json::Value&);
bool CanConvert(const Json::Value& json);
Json::Value ToJson(const T& val);
std::string TypeDescription() const { return "<unknown>"; }
};
@ -119,6 +121,11 @@ namespace TerminalApp::JsonUtils
return json.isString();
}
Json::Value ToJson(const std::string& val)
{
return val;
}
std::string TypeDescription() const
{
return "string";
@ -138,6 +145,11 @@ namespace TerminalApp::JsonUtils
return json.isString();
}
Json::Value ToJson(const std::wstring& val)
{
return til::u16u8(val);
}
std::string TypeDescription() const
{
return "string";
@ -153,6 +165,11 @@ namespace TerminalApp::JsonUtils
{
return winrt::hstring{ til::u8u16(Detail::GetStringView(json)) };
}
Json::Value ToJson(const winrt::hstring& val)
{
return til::u16u8(val);
}
};
#endif
@ -169,6 +186,11 @@ namespace TerminalApp::JsonUtils
return json.isBool();
}
Json::Value ToJson(const bool val)
{
return val;
}
std::string TypeDescription() const
{
return "true | false";
@ -188,6 +210,11 @@ namespace TerminalApp::JsonUtils
return json.isInt();
}
Json::Value ToJson(const int& val)
{
return val;
}
std::string TypeDescription() const
{
return "number";
@ -207,6 +234,11 @@ namespace TerminalApp::JsonUtils
return json.isUInt();
}
Json::Value ToJson(const unsigned int& val)
{
return val;
}
std::string TypeDescription() const
{
return "number (>= 0)";
@ -226,6 +258,11 @@ namespace TerminalApp::JsonUtils
return json.isNumeric();
}
Json::Value ToJson(const float& val)
{
return val;
}
std::string TypeDescription() const
{
return "number";
@ -245,6 +282,11 @@ namespace TerminalApp::JsonUtils
return json.isNumeric();
}
Json::Value ToJson(const double& val)
{
return val;
}
std::string TypeDescription() const
{
return "number";
@ -270,6 +312,11 @@ namespace TerminalApp::JsonUtils
return string.length() == 38 && string.front() == '{' && string.back() == '}';
}
Json::Value ToJson(const GUID& val)
{
return til::u16u8(::Microsoft::Console::Utils::GuidToString(val));
}
std::string TypeDescription() const
{
return "guid";
@ -291,6 +338,11 @@ namespace TerminalApp::JsonUtils
return ConversionTrait<GUID>{}.CanConvert(json);
}
Json::Value ToJson(const winrt::guid& val)
{
return ConversionTrait<GUID>{}.ToJson(val);
}
std::string TypeDescription() const
{
return ConversionTrait<GUID>{}.TypeDescription();
@ -316,6 +368,11 @@ namespace TerminalApp::JsonUtils
return (string.length() == 7 || string.length() == 4) && string.front() == '#';
}
Json::Value ToJson(const til::color& val)
{
return til::u16u8(val.ToHexString(true));
}
std::string TypeDescription() const
{
return "color (#rrggbb, #rgb)";
@ -336,6 +393,11 @@ namespace TerminalApp::JsonUtils
return ConversionTrait<til::color>{}.CanConvert(json);
}
Json::Value ToJson(const winrt::Windows::UI::Color& val)
{
return ConversionTrait<til::color>{}.ToJson(val);
}
std::string TypeDescription() const
{
return ConversionTrait<til::color>{}.TypeDescription();
@ -370,6 +432,18 @@ namespace TerminalApp::JsonUtils
return json.isString();
}
Json::Value ToJson(const T& val)
{
for (const auto& pair : TBase::mappings)
{
if (pair.second == val)
{
return { pair.first.data() };
}
}
FAIL_FAST();
}
std::string TypeDescription() const
{
std::vector<std::string_view> names;
@ -427,6 +501,35 @@ namespace TerminalApp::JsonUtils
return AllClear;
}
Json::Value ToJson(const T& val)
{
if (val == AllClear)
{
return BaseEnumMapper::ToJson(AllClear);
}
else if (val == AllSet)
{
return BaseEnumMapper::ToJson(AllSet);
}
else if (WI_IsSingleFlagSet(val))
{
return BaseEnumMapper::ToJson(val);
}
else
{
Json::Value json{ Json::ValueType::arrayValue };
for (const auto& pair : TBase::mappings)
{
if (pair.second != AllClear &&
(val & pair.second) == pair.second)
{
json.append(BaseEnumMapper::ToJson(pair.second));
}
}
return json;
}
}
bool CanConvert(const Json::Value& json)
{
return BaseEnumMapper::CanConvert(json) || json.isArray();
@ -574,6 +677,21 @@ namespace TerminalApp::JsonUtils
GetValueForKey(json, key1, val1);
GetValuesForKeys(json, std::forward<Args>(args)...);
}
// SetValueForKey, type-deduced, manual converter
template<typename T, typename Converter>
void SetValueForKey(Json::Value& json, std::string_view key, const T& target, Converter&& conv)
{
// demand guarantees that it will return a value or throw an exception
*json.demand(&*key.cbegin(), (&*key.cbegin()) + key.size()) = conv.ToJson(target);
}
// SetValueForKey, type-deduced, with automatic converter
template<typename T>
void SetValueForKey(Json::Value& json, std::string_view key, const T& target)
{
SetValueForKey(json, key, target, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
};
#define JSON_ENUM_MAPPER(...) \

View file

@ -8,6 +8,8 @@
#include "Tab.g.cpp"
#include "Utils.h"
#include "ColorHelper.h"
#include "ActionAndArgs.h"
#include "ActionArgs.h"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
@ -34,6 +36,7 @@ namespace winrt::TerminalApp::implementation
_activePane = _rootPane;
_MakeTabViewItem();
_MakeSwitchToTabCommand();
}
// Method Description:
@ -229,6 +232,9 @@ namespace winrt::TerminalApp::implementation
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
IconSource(GetColoredIcon<winrt::WUX::Controls::IconSource>(_lastIconPath));
_tabViewItem.IconSource(GetColoredIcon<winrt::MUX::Controls::IconSource>(_lastIconPath));
// Update SwitchToTab command's icon
SwitchToTabCommand().IconSource(IconSource());
}
}
@ -266,6 +272,9 @@ namespace winrt::TerminalApp::implementation
// Bubble our current tab text to anyone who's listening for changes.
Title(GetActiveTitle());
// Update SwitchToTab command's name
SwitchToTabCommand().Name(Title());
// Update the UI to reflect the changed
_UpdateTabHeader();
}
@ -1026,6 +1035,35 @@ namespace winrt::TerminalApp::implementation
return _zoomedPane != nullptr;
}
// Method Description:
// - Initializes a SwitchToTab command object for this Tab instance.
// Arguments:
// - <none>
// Return Value:
// - <none>
void Tab::_MakeSwitchToTabCommand()
{
auto focusTabAction = winrt::make_self<implementation::ActionAndArgs>();
auto args = winrt::make_self<implementation::SwitchToTabArgs>();
args->TabIndex(_TabViewIndex);
focusTabAction->Action(ShortcutAction::SwitchToTab);
focusTabAction->Args(*args);
winrt::TerminalApp::Command command;
command.Action(*focusTabAction);
command.Name(Title());
command.IconSource(IconSource());
SwitchToTabCommand(command);
}
void Tab::UpdateTabViewIndex(const uint32_t idx)
{
TabViewIndex(idx);
SwitchToTabCommand().Action().Args().as<implementation::SwitchToTabArgs>()->TabIndex(idx);
}
DEFINE_EVENT(Tab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
DEFINE_EVENT(Tab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
DEFINE_EVENT(Tab, ColorCleared, _colorCleared, winrt::delegate<>);

View file

@ -68,6 +68,8 @@ namespace winrt::TerminalApp::implementation
int GetLeafPaneCount() const noexcept;
void UpdateTabViewIndex(const uint32_t idx);
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
DECLARE_EVENT(ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
@ -76,6 +78,11 @@ namespace winrt::TerminalApp::implementation
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::Controls::IconSource, IconSource, _PropertyChangedHandlers, nullptr);
OBSERVABLE_GETSET_PROPERTY(winrt::TerminalApp::Command, SwitchToTabCommand, _PropertyChangedHandlers, nullptr);
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
// This is needed since Tab is going to be managing its own SwitchToTab command.
OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewIndex, _PropertyChangedHandlers, 0);
private:
std::shared_ptr<Pane> _rootPane{ nullptr };
@ -114,6 +121,8 @@ namespace winrt::TerminalApp::implementation
void _ApplyTabColor(const winrt::Windows::UI::Color& color);
void _ClearTabBackgroundColor();
void _MakeSwitchToTabCommand();
friend class ::TerminalAppLocalTests::TabTests;
};
}

View file

@ -1,11 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "Command.idl";
namespace TerminalApp
{
[default_interface] runtimeclass Tab : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Title { get; };
Windows.UI.Xaml.Controls.IconSource IconSource { get; };
Command SwitchToTabCommand { get; };
UInt32 TabViewIndex { get; };
}
}

View file

@ -166,6 +166,7 @@ namespace winrt::TerminalApp::implementation
auto tab = tabs.GetAt(from.value());
tabs.RemoveAt(from.value());
tabs.InsertAt(to.value(), tab);
page->_UpdateTabIndices();
}
page->_rearranging = false;
@ -687,6 +688,9 @@ namespace winrt::TerminalApp::implementation
auto newTabImpl = winrt::make_self<Tab>(profileGuid, term);
_tabs.Append(*newTabImpl);
// Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command.
newTabImpl->UpdateTabViewIndex(_tabs.Size() - 1);
// Hookup our event handlers to the new terminal
_RegisterTerminalEvents(term, *newTabImpl);
@ -1066,6 +1070,7 @@ namespace winrt::TerminalApp::implementation
_tabs.RemoveAt(tabIndex);
_tabView.TabItems().RemoveAt(tabIndex);
_UpdateTabIndices();
// To close the window here, we need to close the hosting window.
if (_tabs.Size() == 0)
@ -2519,6 +2524,20 @@ namespace winrt::TerminalApp::implementation
return _isAlwaysOnTop;
}
// Method Description:
// - Updates all tabs with their current index in _tabs.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_UpdateTabIndices()
{
for (uint32_t i = 0; i < _tabs.Size(); ++i)
{
_GetStrongTabImpl(i)->UpdateTabViewIndex(i);
}
}
// -------------------------------- WinRT Events ---------------------------------
// Winrt events need a method for adding a callback to the event and removing the callback.
// These macros will define them both for you.

View file

@ -93,6 +93,7 @@ namespace winrt::TerminalApp::implementation
Windows::Foundation::Collections::IObservableVector<TerminalApp::Tab> _tabs;
winrt::com_ptr<Tab> _GetStrongTabImpl(const uint32_t index) const;
winrt::com_ptr<Tab> _GetStrongTabImpl(const ::winrt::TerminalApp::Tab& tab) const;
void _UpdateTabIndices();
bool _isInFocusMode{ false };
bool _isFullscreen{ false };

View file

@ -268,6 +268,21 @@ struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::TerminalApp::LaunchPos
return json.isString();
}
Json::Value ToJson(const ::winrt::TerminalApp::LaunchPosition& val)
{
std::stringstream ss;
if (val.X)
{
ss << val.X.Value();
}
ss << ",";
if (val.Y)
{
ss << val.Y.Value();
}
return ss.str();
}
std::string TypeDescription() const
{
return "x, y";

View file

@ -3491,7 +3491,7 @@ void ConptyRoundtripTests::HyperlinkIdConsistency()
_flushFirstFrame();
hostSm.ProcessString(L"\x1b]8;;http://example.com\x1b/Link\x1b]8;;\x1b/");
hostSm.ProcessString(L"\x1b]8;;http://example.com\x1b\\Link\x1b]8;;\x1b\\");
// For self-generated IDs, conpty will send a custom ID of the form
// {sessionID}-{self-generated ID}

View file

@ -107,6 +107,18 @@ public: \
private: \
type _##name{ __VA_ARGS__ };
// Use this macro to quick implement both the getter and setter for a color property.
// This should only be used for color types where there's no logic in the
// getter/setter beyond just accessing/updating the value.
// This takes advantage of til::color
#define GETSET_COLORPROPERTY(name, ...) \
public: \
winrt::Windows::UI::Color name() const noexcept { return _##name; } \
void name(const winrt::Windows::UI::Color& value) noexcept { _##name = value; } \
\
private: \
til::color _##name{ __VA_ARGS__ };
// Use this macro to quickly implement both the getter and setter for an
// observable property. This is similar to the GETSET_PROPERTY macro above,
// except this will also raise a PropertyChanged event with the name of the

View file

@ -87,7 +87,7 @@ namespace TerminalAppUnitTests
"\"purple\" : \"#881798\","
"\"red\" : \"#C50F1F\","
"\"selectionBackground\" : \"#131313\","
"\"white\" : \"#CCC\","
"\"white\" : \"#CCCCCC\","
"\"yellow\" : \"#C19C00\""
"}" };
@ -110,6 +110,10 @@ namespace TerminalAppUnitTests
const til::color actual{ scheme->Table().at(static_cast<uint32_t>(i)) };
VERIFY_ARE_EQUAL(expected, actual);
}
Log::Comment(L"Roundtrip Test for Color Scheme");
Json::Value outJson{ scheme->ToJson() };
VERIFY_ARE_EQUAL(schemeObject, outJson);
}
void JsonTests::ProfileGeneratesGuid()

View file

@ -293,11 +293,24 @@ namespace TerminalAppUnitTests
// versions.
template<typename TExpected, typename TJson>
static void TryBasicType(TExpected&& expected, TJson&& json)
static void TryBasicType(TExpected&& expected, TJson&& json, std::optional<Json::Value> overrideToJsonOutput = std::nullopt)
{
// test FromJson
Json::Value jsonObject{ json };
const auto value{ GetValue<TExpected>(jsonObject) };
VERIFY_ARE_EQUAL(expected, value, NoThrowString{}.Format(L"(type: %hs)", typeid(TExpected).name()));
// test ToJson
{
const std::string key{ "myKey" };
Json::Value expectedJson{};
expectedJson[key] = til::coalesce_value(overrideToJsonOutput, jsonObject);
Json::Value toJsonResult{};
SetValueForKey(toJsonResult, key, expected);
VERIFY_ARE_EQUAL(expectedJson, toJsonResult);
}
}
void JsonUtilsTests::BasicTypeConversion()
@ -305,7 +318,7 @@ namespace TerminalAppUnitTests
// Battery of all basic types ;P
TryBasicType(std::string{ "hello" }, "hello");
TryBasicType(int{ -1024 }, -1024);
TryBasicType(unsigned int{ 1024 }, 1024);
TryBasicType(std::numeric_limits<unsigned int>::max(), std::numeric_limits<unsigned int>::max());
TryBasicType(false, false);
TryBasicType(1.0f, 1.0f);
@ -318,9 +331,10 @@ namespace TerminalAppUnitTests
// double -> float
TryBasicType(1.0f, 1.0);
TryBasicType(til::color{ 0xab, 0xcd, 0xef }, "#abcdef");
TryBasicType(til::color{ 0xab, 0xcd, 0xef }, "#ABCDEF");
TryBasicType(til::color{ 0xcc, 0xcc, 0xcc }, "#CCC", "#CCCCCC");
static const std::string testGuidString{ "{AA8147AA-E289-4508-BE83-FB68361EF2F3}" }; // can't use a string_view; jsoncpp hates it
static const std::string testGuidString{ "{aa8147aa-e289-4508-be83-fb68361ef2f3}" }; // can't use a string_view; jsoncpp hates it
static const GUID testGuid{ 0xaa8147aa, 0xe289, 0x4508, { 0xbe, 0x83, 0xfb, 0x68, 0x36, 0x1e, 0xf2, 0xf3 } };
TryBasicType(testGuid, testGuidString);
@ -371,6 +385,19 @@ namespace TerminalAppUnitTests
// Unknown value should produce something?
Json::Value stringUnknown{ "unknown" };
VERIFY_THROWS_SPECIFIC(GetValue<JsonTestEnum>(stringUnknown), DeserializationError, _ReturnTrueForException);
// SetValueForKey
{
const std::string key{ "myKey" };
const auto val{ JsonTestEnum::Third };
Json::Value expected{};
expected[key] = "third";
Json::Value json{};
SetValueForKey(json, key, val);
VERIFY_ARE_EQUAL(expected, json);
}
}
void JsonUtilsTests::FlagMapper()
@ -385,16 +412,64 @@ namespace TerminalAppUnitTests
Json::Value stringAll{ "all" };
VERIFY_ARE_EQUAL(JsonTestFlags::All, GetValue<JsonTestFlags>(stringAll));
{
const std::string key{ "myKey" };
const auto val{ JsonTestFlags::Third };
Json::Value expected{};
expected[key] = "third";
Json::Value json{};
SetValueForKey(json, key, val);
VERIFY_ARE_EQUAL(expected, json);
}
{
const std::string key{ "myKey" };
const auto val{ JsonTestFlags::All };
Json::Value expected{};
expected[key] = "all";
Json::Value json{};
SetValueForKey(json, key, val);
VERIFY_ARE_EQUAL(expected, json);
}
// Multiple flags
Json::Value arrayFirstSecond{ Json::arrayValue };
arrayFirstSecond.append({ "first" });
arrayFirstSecond.append({ "second" });
VERIFY_ARE_EQUAL(JsonTestFlags::First | JsonTestFlags::Second, GetValue<JsonTestFlags>(arrayFirstSecond));
{
const std::string key{ "myKey" };
const auto val{ JsonTestFlags::First | JsonTestFlags::Second };
Json::Value expected{};
expected[key] = arrayFirstSecond;
Json::Value json{};
SetValueForKey(json, key, val);
VERIFY_ARE_EQUAL(expected, json);
}
// No flags
Json::Value emptyArray{ Json::arrayValue };
VERIFY_ARE_EQUAL(JsonTestFlags::None, GetValue<JsonTestFlags>(emptyArray));
{
const std::string key{ "myKey" };
const auto val{ JsonTestFlags::None };
Json::Value expected{};
expected[key] = "none";
Json::Value json{};
SetValueForKey(json, key, val);
VERIFY_ARE_EQUAL(expected, json);
}
// Stacking Always + Any
Json::Value arrayAllFirst{ Json::arrayValue };
arrayAllFirst.append({ "all" });

View file

@ -42,7 +42,9 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
r{ 0 },
g{ 0 },
b{ 0 },
a{ 0 } {}
a{ 0 }
{
}
constexpr color(uint8_t _r, uint8_t _g, uint8_t _b) noexcept :
r{ _r },

View file

@ -68,14 +68,15 @@ static constexpr bool _isC0Code(const wchar_t wch) noexcept
}
// Routine Description:
// - Determines if a character is a C1 CSI (Control Sequence Introducer)
// This is a single-character way to start a control sequence, as opposed to "ESC[".
// - Determines if a character is a C1 control characters.
// This is a single-character way to start a control sequence, as opposed to using ESC
// and their 7-bit equivalent.
//
// Not all single-byte codepages support C1 control codes--in some, the range that would
// be used for C1 codes are instead used for additional graphic characters.
//
// However, we do not need to worry about confusion whether a single byte \x9b in a
// single-byte stream represents a C1 CSI or some other glyph, because by the time we
// However, we do not need to worry about confusion whether a single byte, for example,
// \x9b in a single-byte stream represents a C1 CSI or some other glyph, because by the time we
// get here, everything is Unicode. Knowing whether a single-byte \x9b represents a
// single-character C1 CSI or some other glyph is handled by MultiByteToWideChar before
// we get here (if the stream was not already UTF-16). For instance, in CP_ACP, if a
@ -86,24 +87,21 @@ static constexpr bool _isC0Code(const wchar_t wch) noexcept
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isC1Csi(const wchar_t wch) noexcept
static constexpr bool _isC1ControlCharacter(const wchar_t wch) noexcept
{
return wch == L'\x9b';
return (wch >= L'\x80' && wch <= L'\x9F');
}
// Routine Description:
// - Determines if a character is a C1 DCS (Device Control Strings)
// This is a single-character way to start a control sequence, as opposed to "ESC P".
//
// See the comment above _isC1Csi for more information on how this is impacted by codepages.
// - Convert a C1 control characters to their 7-bit equivalent.
//
// Arguments:
// - wch - Character to check.
// - wch - Character to convert.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isC1Dcs(const wchar_t wch) noexcept
// - The 7-bit equivalent of the 8-bit control characters.
static constexpr wchar_t _c1To7Bit(const wchar_t wch) noexcept
{
return wch == L'\x90';
return wch - L'\x40';
}
// Routine Description:
@ -144,7 +142,7 @@ static constexpr bool _isEscape(const wchar_t wch) noexcept
}
// Routine Description:
// - Determines if a character is a delimiter between two parameters in a "control sequence".
// - Determines if a character is a delimiter between two parameters in an escape sequence.
// Arguments:
// - wch - Character to check.
// Return Value:
@ -213,17 +211,6 @@ static constexpr bool _isParameterInvalid(const wchar_t wch) noexcept
return _isCsiInvalid(wch) || _isCsiPrivateMarker(wch);
}
// Routine Description:
// - Determines if a character is a string terminator.
// Arguments:
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isStringTerminator(const wchar_t wch) noexcept
{
return wch == L'\x9C';
}
// Routine Description:
// - Determines if a character is a string terminator indicator.
// Arguments:
@ -287,17 +274,6 @@ static constexpr bool _isOscDelimiter(const wchar_t wch) noexcept
return wch == L';'; // 0x3B
}
// Routine Description:
// - Determines if a character should be initiate the end of an OSC sequence.
// Arguments:
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isOscTerminationInitiator(const wchar_t wch) noexcept
{
return wch == AsciiChars::ESC;
}
// Routine Description:
// - Determines if a character should be ignored in a operating system control sequence
// Arguments:
@ -320,7 +296,7 @@ static constexpr bool _isOscInvalid(const wchar_t wch) noexcept
// - True if it is. False if it isn't.
static constexpr bool _isOscTerminator(const wchar_t wch) noexcept
{
return wch == AsciiChars::BEL || _isStringTerminator(wch); // Bell character or C1 terminator
return wch == AsciiChars::BEL; // Bell character
}
// Routine Description:
@ -335,17 +311,6 @@ static constexpr bool _isDcsIndicator(const wchar_t wch) noexcept
return wch == L'P'; // 0x50
}
// Routine Description:
// - Determines if a character should initiate the end of a DCS sequence.
// Arguments:
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isDcsTerminationInitiator(const wchar_t wch) noexcept
{
return wch == AsciiChars::ESC;
}
// Routine Description:
// - Determines if a character is valid for a DCS pass through sequence.
// Arguments:
@ -358,6 +323,42 @@ static constexpr bool _isDcsPassThroughValid(const wchar_t wch) noexcept
return wch >= AsciiChars::SPC && wch < AsciiChars::DEL;
}
// Routine Description:
// - Determines if a character is "start of string" beginning
// indicator.
// Arguments:
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isSosIndicator(const wchar_t wch) noexcept
{
return wch == L'X'; // 0x58
}
// Routine Description:
// - Determines if a character is "private message" beginning
// indicator.
// Arguments:
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isPmIndicator(const wchar_t wch) noexcept
{
return wch == L'^'; // 0x5E
}
// Routine Description:
// - Determines if a character is "application program command" beginning
// indicator.
// Arguments:
// - wch - Character to check.
// Return Value:
// - True if it is. False if it isn't.
static constexpr bool _isApcIndicator(const wchar_t wch) noexcept
{
return wch == L'_'; // 0x5F
}
// Routine Description:
// - Determines if a character indicates an action that should be taken in the ground state -
// These are C0 characters and the C1 [single-character] CSI.
@ -367,7 +368,7 @@ static constexpr bool _isDcsPassThroughValid(const wchar_t wch) noexcept
// - True if it is. False if it isn't.
static constexpr bool _isActionableFromGround(const wchar_t wch) noexcept
{
return (wch <= AsciiChars::US) || _isC1Csi(wch) || _isC1Dcs(wch) || _isDelete(wch);
return (wch <= AsciiChars::US) || _isC1ControlCharacter(wch) || _isDelete(wch);
}
#pragma warning(pop)
@ -926,12 +927,42 @@ void StateMachine::_EnterDcsTermination() noexcept
_trace.TraceStateChange(L"DcsTermination");
}
// Routine Description:
// - Moves the state machine into the SosPmApcString state.
// This state is entered:
// 1. When the Sos character is seen after an Escape entry
// 2. When the Pm character is seen after an Escape entry
// 3. When the Apc character is seen after an Escape entry
// Arguments:
// - <none>
// Return Value:
// - <none>
void StateMachine::_EnterSosPmApcString() noexcept
{
_state = VTStates::SosPmApcString;
_trace.TraceStateChange(L"SosPmApcString");
}
// Routine Description:
// - Moves the state machine into the SosPmApcStringTermination state.
// This state is entered:
// 1. When an ESC is seen in a SOS/PM/APC string. This escape will be followed by a
// '\', as to encode a 0x9C as a 7-bit ASCII char stream.
// Arguments:
// - <none>
// Return Value:
// - <none>
void StateMachine::_EnterSosPmApcTermination() noexcept
{
_state = VTStates::SosPmApcTermination;
_trace.TraceStateChange(L"SosPmApcStringTermination");
}
// Routine Description:
// - Processes a character event into an Action that occurs while in the Ground state.
// Events in this state will:
// 1. Execute C0 control characters
// 2. Handle a C1 Control Sequence Introducer
// 3. Print all other characters
// 2. Print all other characters
// Arguments:
// - wch - Character that triggered the event
// Return Value:
@ -943,14 +974,6 @@ void StateMachine::_EventGround(const wchar_t wch)
{
_ActionExecute(wch);
}
else if (_isC1Csi(wch) && _isInAnsiMode)
{
_EnterCsiEntry();
}
else if (_isC1Dcs(wch) && _isInAnsiMode)
{
_EnterDcsEntry();
}
else
{
_ActionPrint(wch);
@ -1019,6 +1042,10 @@ void StateMachine::_EventEscape(const wchar_t wch)
{
_EnterDcsEntry();
}
else if (_isSosIndicator(wch) || _isPmIndicator(wch) || _isApcIndicator(wch))
{
_EnterSosPmApcString();
}
else
{
_ActionEscDispatch(wch);
@ -1299,7 +1326,7 @@ void StateMachine::_EventOscString(const wchar_t wch)
_ActionOscDispatch(wch);
_EnterGround();
}
else if (_isOscTerminationInitiator(wch))
else if (_isEscape(wch))
{
_EnterOscTermination();
}
@ -1322,13 +1349,6 @@ void StateMachine::_EventOscString(const wchar_t wch)
// - wch - Character that triggered the event
// Return Value:
// - <none>
void StateMachine::_EventOscTermination(const wchar_t wch)
{
_trace.TraceOnEvent(L"OscTermination");
_ActionOscDispatch(wch);
_EnterGround();
}
// Routine Description:
// - Processes a character event into an Action that occurs while in the Ss3Entry state.
@ -1497,24 +1517,16 @@ void StateMachine::_EventDcsEntry(const wchar_t wch)
// Routine Description:
// - Processes a character event into an Action that occurs while in the DcsIgnore state.
// Events in this state will:
// 1. Enter ground on a String terminator
// 2. Ignore everything else.
// In this state the entire DCS string is considered invalid and we will ignore everything.
// The termination state is handled outside when an ESC is seen.
// Arguments:
// - wch - Character that triggered the event
// Return Value:
// - <none>
void StateMachine::_EventDcsIgnore(const wchar_t wch) noexcept
void StateMachine::_EventDcsIgnore() noexcept
{
_trace.TraceOnEvent(L"DcsIgnore");
if (_isStringTerminator(wch))
{
_EnterGround();
}
else
{
_ActionIgnore();
}
_ActionIgnore();
}
// Routine Description:
@ -1603,10 +1615,9 @@ void StateMachine::_EventDcsParam(const wchar_t wch)
// Routine Description:
// - Processes a character event into an Action that occurs while in the DcsPassThrough state.
// Events in this state will:
// 1. Enter ground on a String terminator
// 2. Pass through if character is valid.
// 3. If we see a ESC, enter the DcsTermination state.
// 4. Ignore everything else.
// 1. Pass through if character is valid.
// 2. If we see a ESC, enter the DcsTermination state.
// 3. Ignore everything else.
// Arguments:
// - wch - Character that triggered the event
// Return Value:
@ -1614,16 +1625,11 @@ void StateMachine::_EventDcsParam(const wchar_t wch)
void StateMachine::_EventDcsPassThrough(const wchar_t wch)
{
_trace.TraceOnEvent(L"DcsPassThrough");
if (_isStringTerminator(wch))
{
// TODO:GH#7316: The Dcs sequence has successfully terminated. This is where we'd be dispatching the DCS command.
_EnterGround();
}
if (_isC0Code(wch) || _isDcsPassThroughValid(wch))
{
_ActionDcsPassThrough(wch);
}
else if (_isDcsTerminationInitiator(wch))
else if (_isEscape(wch))
{
_EnterDcsTermination();
}
@ -1634,21 +1640,52 @@ void StateMachine::_EventDcsPassThrough(const wchar_t wch)
}
// Routine Description:
// - Handle the two-character termination of a DCS sequence.
// - Handle SOS/PM/APC string.
// Events in this state will:
// 1. Enter ground on a string terminator
// 2. Pass on everything else as the start of a regular escape sequence
// 1. If we see a ESC, enter the SosPmApcTermination state.
// 2. Ignore everything else.
// Arguments:
// - wch - Character that triggered the event
// Return Value:
// - <none>
void StateMachine::_EventDcsTermination(const wchar_t wch)
void StateMachine::_EventSosPmApcString(const wchar_t wch) noexcept
{
_trace.TraceOnEvent(L"DcsTermination");
_trace.TraceOnEvent(L"SosPmApcString");
if (_isEscape(wch))
{
_EnterSosPmApcTermination();
}
else
{
_ActionIgnore();
}
}
// Routine Description:
// - Handle "Variable Length String" termination.
// Events in this state will:
// 1. Trigger the corresponding action and enter ground if we see a string terminator,
// 2. Otherwise treat this as a normal escape character event.
// Arguments:
// - wch - Character that triggered the event
// Return Value:
// - <none>
void StateMachine::_EventVariableLengthStringTermination(const wchar_t wch)
{
if (_isStringTerminatorIndicator(wch))
{
// TODO: The Dcs sequence has successfully terminated. This is where we'd be dispatching the DCS command.
if (_state == VTStates::OscTermination)
{
_ActionOscDispatch(wch);
}
else if (_state == VTStates::DcsTermination)
{
// TODO:GH#7316: The Dcs sequence has successfully terminated. This is where we'd be dispatching the DCS command.
}
else if (_state == VTStates::SosPmApcTermination)
{
// We don't support any SOS/PM/APC control string yet.
}
_EnterGround();
}
else
@ -1680,12 +1717,40 @@ void StateMachine::ProcessCharacter(const wchar_t wch)
_ActionExecute(wch);
_EnterGround();
}
else if (_isEscape(wch) && _state != VTStates::OscString && _state != VTStates::DcsPassThrough)
// Preprocess C1 control characters and treat them as ESC + their 7-bit equivalent.
else if (_isC1ControlCharacter(wch))
{
// When we are in "Variable Length String" state, a C1 control character
// should effectively acts as an ESC and move us into the corresponding
// termination state.
if (_IsVariableLengthStringState())
{
if (_state == VTStates::OscString)
{
_EnterOscTermination();
}
else if (_state == VTStates::DcsPassThrough)
{
_EnterDcsTermination();
}
else if (_state == VTStates::SosPmApcString)
{
_EnterSosPmApcTermination();
}
_EventVariableLengthStringTermination(_c1To7Bit(wch));
}
// Enter Escape state and pass the converted 7-bit character.
else
{
_EnterEscape();
_EventEscape(_c1To7Bit(wch));
}
}
// Don't go to escape from the "Variable Length String" state - ESC (and C1 String Terminator)
// can be used to terminate variable length control string.
else if (_isEscape(wch) && !_IsVariableLengthStringState())
{
// Don't go to escape from the OSC string state - ESC can be used to
// terminate OSC strings.
//
// Same for DCS pass through state.
_EnterEscape();
}
else
@ -1712,7 +1777,7 @@ void StateMachine::ProcessCharacter(const wchar_t wch)
case VTStates::OscString:
return _EventOscString(wch);
case VTStates::OscTermination:
return _EventOscTermination(wch);
return _EventVariableLengthStringTermination(wch);
case VTStates::Ss3Entry:
return _EventSs3Entry(wch);
case VTStates::Ss3Param:
@ -1722,7 +1787,7 @@ void StateMachine::ProcessCharacter(const wchar_t wch)
case VTStates::DcsEntry:
return _EventDcsEntry(wch);
case VTStates::DcsIgnore:
return _EventDcsIgnore(wch);
return _EventDcsIgnore();
case VTStates::DcsIntermediate:
return _EventDcsIntermediate(wch);
case VTStates::DcsParam:
@ -1730,7 +1795,11 @@ void StateMachine::ProcessCharacter(const wchar_t wch)
case VTStates::DcsPassThrough:
return _EventDcsPassThrough(wch);
case VTStates::DcsTermination:
return _EventDcsTermination(wch);
return _EventVariableLengthStringTermination(wch);
case VTStates::SosPmApcString:
return _EventSosPmApcString(wch);
case VTStates::SosPmApcTermination:
return _EventVariableLengthStringTermination(wch);
default:
return;
}
@ -1952,3 +2021,16 @@ void StateMachine::_AccumulateTo(const wchar_t wch, size_t& value) noexcept
value = MAX_PARAMETER_VALUE;
}
}
// Routine Description:
// - Determines if the engine is in "Variable Length String" state, which is a combination
// of all states that are expecting a string that has a undetermined length.
//
// Arguments:
// - <none>
// Return Value:
// - True if it is. False if it isn't.
const bool StateMachine::_IsVariableLengthStringState() const noexcept
{
return _state == VTStates::OscString || _state == VTStates::DcsPassThrough || _state == VTStates::SosPmApcString;
}

View file

@ -86,6 +86,8 @@ namespace Microsoft::Console::VirtualTerminal
void _EnterDcsIntermediate() noexcept;
void _EnterDcsPassThrough() noexcept;
void _EnterDcsTermination() noexcept;
void _EnterSosPmApcString() noexcept;
void _EnterSosPmApcTermination() noexcept;
void _EventGround(const wchar_t wch);
void _EventEscape(const wchar_t wch);
@ -96,18 +98,19 @@ namespace Microsoft::Console::VirtualTerminal
void _EventCsiParam(const wchar_t wch);
void _EventOscParam(const wchar_t wch) noexcept;
void _EventOscString(const wchar_t wch);
void _EventOscTermination(const wchar_t wch);
void _EventSs3Entry(const wchar_t wch);
void _EventSs3Param(const wchar_t wch);
void _EventVt52Param(const wchar_t wch);
void _EventDcsEntry(const wchar_t wch);
void _EventDcsIgnore(const wchar_t wch) noexcept;
void _EventDcsIgnore() noexcept;
void _EventDcsIntermediate(const wchar_t wch);
void _EventDcsParam(const wchar_t wch);
void _EventDcsPassThrough(const wchar_t wch);
void _EventDcsTermination(const wchar_t wch);
void _EventSosPmApcString(const wchar_t wch) noexcept;
void _EventVariableLengthStringTermination(const wchar_t wch);
void _AccumulateTo(const wchar_t wch, size_t& value) noexcept;
const bool _IsVariableLengthStringState() const noexcept;
enum class VTStates
{
@ -129,7 +132,9 @@ namespace Microsoft::Console::VirtualTerminal
DcsIntermediate,
DcsParam,
DcsPassThrough,
DcsTermination
DcsTermination,
SosPmApcString,
SosPmApcTermination
};
Microsoft::Console::VirtualTerminal::ParserTracing _trace;

View file

@ -56,7 +56,7 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final
TEST_METHOD(TestEscapePath)
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Data:uiTest", L"{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}") // one value for each type of state test below.
TEST_METHOD_PROPERTY(L"Data:uiTest", L"{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}") // one value for each type of state test below.
END_TEST_METHOD_PROPERTIES()
size_t uiTest;
@ -66,7 +66,7 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final
StateMachine mach(std::move(engine));
// The OscString state shouldn't escape out after an ESC.
// Same for DcsPassThrough state.
// Same for DcsPassThrough and SosPmApcString state.
bool shouldEscapeOut = true;
switch (uiTest)
@ -181,6 +181,19 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final
mach._state = StateMachine::VTStates::DcsTermination;
break;
}
case 18:
{
Log::Comment(L"Escape from SosPmApcString");
shouldEscapeOut = false;
mach._state = StateMachine::VTStates::SosPmApcString;
break;
}
case 19:
{
Log::Comment(L"Escape from SosPmApcTermination");
mach._state = StateMachine::VTStates::SosPmApcTermination;
break;
}
}
mach.ProcessCharacter(AsciiChars::ESC);
@ -405,6 +418,19 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestC1Osc)
{
auto dispatch = std::make_unique<DummyDispatch>();
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
StateMachine mach(std::move(engine));
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(L'\x9d');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam);
mach.ProcessCharacter(AsciiChars::BEL);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestOscStringSimple)
{
auto dispatch = std::make_unique<DummyDispatch>();
@ -596,6 +622,35 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestOscStringInvalidTermination)
{
auto dispatch = std::make_unique<DummyDispatch>();
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
StateMachine mach(std::move(engine));
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L']');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam);
mach.ProcessCharacter(L'1');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam);
mach.ProcessCharacter(L';');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscString);
mach.ProcessCharacter(L's');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscString);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscTermination);
mach.ProcessCharacter(L'['); // This is not a string terminator.
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiEntry);
mach.ProcessCharacter(L'4');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiParam);
mach.ProcessCharacter(L';');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiParam);
mach.ProcessCharacter(L'm');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestDcsEntry)
{
auto dispatch = std::make_unique<DummyDispatch>();
@ -752,6 +807,143 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final
mach.ProcessCharacter(L'\\');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestDcsInvalidTermination)
{
auto dispatch = std::make_unique<DummyDispatch>();
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
StateMachine mach(std::move(engine));
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'P');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsEntry);
mach.ProcessCharacter(L'q');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsPassThrough);
mach.ProcessCharacter(L'#');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsPassThrough);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsTermination);
mach.ProcessCharacter(L'['); // This is not a string terminator.
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiEntry);
mach.ProcessCharacter(L'4');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiParam);
mach.ProcessCharacter(L';');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiParam);
mach.ProcessCharacter(L'm');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestSosPmApcString)
{
auto dispatch = std::make_unique<DummyDispatch>();
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
StateMachine mach(std::move(engine));
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'X');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'1');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'2');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcTermination);
mach.ProcessCharacter(L'\\');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'^');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'3');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'4');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcTermination);
mach.ProcessCharacter(L'\\');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'_');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'5');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'6');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcTermination);
mach.ProcessCharacter(L'\\');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
TEST_METHOD(TestC1StringTerminator)
{
auto dispatch = std::make_unique<DummyDispatch>();
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
StateMachine mach(std::move(engine));
// C1 ST should terminate OSC string.
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L']');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam);
mach.ProcessCharacter(L'1');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam);
mach.ProcessCharacter(L';');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscString);
mach.ProcessCharacter(L's');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscString);
mach.ProcessCharacter(L'\x9c');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
// C1 ST should terminate DCS passthrough string.
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'P');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsEntry);
mach.ProcessCharacter(L'q');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsPassThrough);
mach.ProcessCharacter(L'#');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::DcsPassThrough);
mach.ProcessCharacter(L'1');
mach.ProcessCharacter(L'\x9c');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
// C1 ST should terminate SOS/PM/APC string.
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'X');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'1');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'\x9c');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'^');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'2');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'\x9c');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
mach.ProcessCharacter(AsciiChars::ESC);
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Escape);
mach.ProcessCharacter(L'_');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'3');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::SosPmApcString);
mach.ProcessCharacter(L'\x9c');
VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground);
}
};
class StatefulDispatch final : public TermDispatch