Compare commits
280 Commits
dev/miniks
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b05df6cb3 | ||
|
|
43e838de9a | ||
|
|
7c3378a835 | ||
|
|
4eeaddc583 | ||
|
|
26ca73b823 | ||
|
|
e6aeb8a017 | ||
|
|
042cbea767 | ||
|
|
c2db1e95db | ||
|
|
990628a78b | ||
|
|
5b2fd70940 | ||
|
|
d1e58bd71e | ||
|
|
2ea4742f07 | ||
|
|
4daed9d946 | ||
|
|
2bf5d18c84 | ||
|
|
8e3f27f8fb | ||
|
|
1c97d20c13 | ||
|
|
ce4fd2970a | ||
|
|
242833f8b2 | ||
|
|
e21f9f5ac6 | ||
|
|
6d44e0d651 | ||
|
|
5a1c931f77 | ||
|
|
60437b890e | ||
|
|
fc9a46dbbd | ||
|
|
1fa3177f77 | ||
|
|
3f7f6ac34c | ||
|
|
d51d8dc768 | ||
|
|
1df3182865 | ||
|
|
b603929214 | ||
|
|
7e8600147e | ||
|
|
5a518e5e58 | ||
|
|
b3aab8c158 | ||
|
|
87004994f7 | ||
|
|
c095a678a5 | ||
|
|
84bda067c5 | ||
|
|
4a95d94c55 | ||
|
|
6928c5a885 | ||
|
|
7a75e508d6 | ||
|
|
16b8ea14d6 | ||
|
|
4f39e8e752 | ||
|
|
293ad2757b | ||
|
|
403b793179 | ||
|
|
ae550e0969 | ||
|
|
ccf9f03ed3 | ||
|
|
895ac06dbd | ||
|
|
00f5fbaf3d | ||
|
|
4099aacacb | ||
|
|
1ad7a25cb2 | ||
|
|
c1d27774b4 | ||
|
|
8eaaa8a2b7 | ||
|
|
90452664ff | ||
|
|
df7c3ccc3b | ||
|
|
743283e434 | ||
|
|
4a4a41eadf | ||
|
|
60d681d564 | ||
|
|
bd7cd5512d | ||
|
|
30e363e7ac | ||
|
|
9d911c01fb | ||
|
|
98806e27b1 | ||
|
|
e996fadbb6 | ||
|
|
5662cc1710 | ||
|
|
55151a4a04 | ||
|
|
6e8388e683 | ||
|
|
8bdae31f6b | ||
|
|
004da88bba | ||
|
|
f78687453c | ||
|
|
afcc930119 | ||
|
|
33321b8596 | ||
|
|
02b120236c | ||
|
|
f86045e041 | ||
|
|
cb732a4bcc | ||
|
|
d2d462fc48 | ||
|
|
cb96aa718f | ||
|
|
9b203d40c1 | ||
|
|
8d12388915 | ||
|
|
9dc38ad0f5 | ||
|
|
9e86e29584 | ||
|
|
cd768934be | ||
|
|
7a1932c556 | ||
|
|
d33ca7e8eb | ||
|
|
f0b8875770 | ||
|
|
91ccbb79f0 | ||
|
|
4fc607a44d | ||
|
|
ba79d53887 | ||
|
|
22887d721f | ||
|
|
2608e94822 | ||
|
|
e401edf9ef | ||
|
|
4a114971f9 | ||
|
|
09cc5f492c | ||
|
|
386ae04edf | ||
|
|
da4ca86680 | ||
|
|
9ec57a7d3c | ||
|
|
6f051140da | ||
|
|
3cf31fbde4 | ||
|
|
c3b3f5f0ba | ||
|
|
f28ec65843 | ||
|
|
40893b2823 | ||
|
|
9539ec3679 | ||
|
|
49b9d41caf | ||
|
|
d1671a0acd | ||
|
|
206131d83a | ||
|
|
1e3236c87d | ||
|
|
f6cc0202b1 | ||
|
|
ef83aa3c41 | ||
|
|
468c8c6728 | ||
|
|
d1981b531f | ||
|
|
b70ffdf790 | ||
|
|
c0335940a0 | ||
|
|
5d823f538c | ||
|
|
f91b53d5fd | ||
|
|
863e3e5c22 | ||
|
|
515c9f2c42 | ||
|
|
6c7a3aca3f | ||
|
|
2f8b3c45d3 | ||
|
|
abf8805e00 | ||
|
|
c17f448d73 | ||
|
|
88d1527985 | ||
|
|
892cf05fe6 | ||
|
|
1377dbcbf4 | ||
|
|
c3ddfab0bd | ||
|
|
be50e563e6 | ||
|
|
cb037f3953 | ||
|
|
27f7ce7c6e | ||
|
|
1c7ee65c5f | ||
|
|
c5cf7b817a | ||
|
|
c28efc3c4f | ||
|
|
b2cfd0adad | ||
|
|
230b86c990 | ||
|
|
7a03f75ee9 | ||
|
|
7ab4d45a9d | ||
|
|
5ba992a803 | ||
|
|
5330759c0f | ||
|
|
9279b7a73d | ||
|
|
97c2ccf08b | ||
|
|
4c75ffb327 | ||
|
|
c808ed94a5 | ||
|
|
614507b95b | ||
|
|
7803efa6fe | ||
|
|
a51091c615 | ||
|
|
6c0e6d94cd | ||
|
|
9283781579 | ||
|
|
f357e379fc | ||
|
|
0488c5322c | ||
|
|
2fdc88f7ea | ||
|
|
64f10a0c9d | ||
|
|
ac310d98b7 | ||
|
|
4aecbf3833 | ||
|
|
dbbe820ae4 | ||
|
|
6acb9f8c90 | ||
|
|
c15b808142 | ||
|
|
a5bed25417 | ||
|
|
17e0c11840 | ||
|
|
f897ce0a9f | ||
|
|
55b6ace79f | ||
|
|
58efe791d1 | ||
|
|
3d370dc652 | ||
|
|
64e3c848c0 | ||
|
|
e238dcb84d | ||
|
|
6f991d312e | ||
|
|
2c4b868b20 | ||
|
|
4814c4f81d | ||
|
|
5a0deca3d8 | ||
|
|
eecdd53eb8 | ||
|
|
20b7fe4ef4 | ||
|
|
b8b0dd75cf | ||
|
|
3d64921120 | ||
|
|
7fcff4d33a | ||
|
|
5d082ffe67 | ||
|
|
97c52c6503 | ||
|
|
6eea6a3ced | ||
|
|
66fd9c367d | ||
|
|
93d266925c | ||
|
|
a50c48cd60 | ||
|
|
8943f68d4d | ||
|
|
baefa46238 | ||
|
|
c4a9752be1 | ||
|
|
acac35023d | ||
|
|
24b8c13bd0 | ||
|
|
e9a7053629 | ||
|
|
aecd99e0ca | ||
|
|
dcc2799457 | ||
|
|
d9ffca6614 | ||
|
|
01e3fda91b | ||
|
|
93ae6b6dba | ||
|
|
a02a29783e | ||
|
|
e1cdc2776f | ||
|
|
a2721c1043 | ||
|
|
a34cfa4e78 | ||
|
|
c241f83fb3 | ||
|
|
849243af99 | ||
|
|
fe82e97ff6 | ||
|
|
c5d5500758 | ||
|
|
bc642bbf2a | ||
|
|
7ccd1f6f1a | ||
|
|
b07c1e49da | ||
|
|
c03677b0c9 | ||
|
|
e6c71cb62a | ||
|
|
e7a1a675af | ||
|
|
aee803e694 | ||
|
|
20a288020e | ||
|
|
70fd03f247 | ||
|
|
4e0f31337d | ||
|
|
60b44c856e | ||
|
|
1c6aa4d109 | ||
|
|
858905f492 | ||
|
|
0a30b856a9 | ||
|
|
f215b56ca3 | ||
|
|
b617c434a1 | ||
|
|
b759bdb711 | ||
|
|
a3c8b2d8aa | ||
|
|
cd7235661e | ||
|
|
d29be591a8 | ||
|
|
eb8bb09e5b | ||
|
|
7bf9225c15 | ||
|
|
8bad88cf9c | ||
|
|
46f7772261 | ||
|
|
14c94f5963 | ||
|
|
158a1708a6 | ||
|
|
ef4aed944a | ||
|
|
dd0f7b701a | ||
|
|
8b669b5484 | ||
|
|
f49ae2451d | ||
|
|
5c5c437ab8 | ||
|
|
6ee8099a2c | ||
|
|
2f5ba9471d | ||
|
|
bf90869f30 | ||
|
|
8f3ad5dcd9 | ||
|
|
f486a6504c | ||
|
|
982d30467b | ||
|
|
52d0e3cd52 | ||
|
|
878ed57db6 | ||
|
|
bb2920ec01 | ||
|
|
ecf99fac23 | ||
|
|
c86038926d | ||
|
|
52b05e065e | ||
|
|
81a80257c9 | ||
|
|
76de2aedc2 | ||
|
|
c390b61648 | ||
|
|
04f5ee7ebf | ||
|
|
d0ff5f6b5e | ||
|
|
3a91fc0ab4 | ||
|
|
0c3841a8b0 | ||
|
|
1ea9fc26c8 | ||
|
|
e1d15105d7 | ||
|
|
d321ec084c | ||
|
|
f33c69d8b4 | ||
|
|
4351f32f5d | ||
|
|
ea2bd42ff4 | ||
|
|
1f8264d86b | ||
|
|
30b8335479 | ||
|
|
93b79fb23c | ||
|
|
efb1fddb99 | ||
|
|
7bc5de613c | ||
|
|
bcbe246a93 | ||
|
|
03e25f12e9 | ||
|
|
7062a830b8 | ||
|
|
53df6c7f96 | ||
|
|
81b7e54659 | ||
|
|
3255177dd0 | ||
|
|
b62f5ea850 | ||
|
|
7b8806b1fe | ||
|
|
8c5041b2ae | ||
|
|
a511ab0bc7 | ||
|
|
501c47adb2 | ||
|
|
72121721f3 | ||
|
|
3e80b6a466 | ||
|
|
a80e1d3f73 | ||
|
|
f45df9a717 | ||
|
|
b37f69826e | ||
|
|
ebfd852970 | ||
|
|
b2e76c1812 | ||
|
|
2179e16e3d | ||
|
|
fafc0e1316 | ||
|
|
ca6dff9f20 | ||
|
|
186ff8f638 | ||
|
|
37810aac71 | ||
|
|
33bc88b225 | ||
|
|
d56137876e | ||
|
|
f928d41917 | ||
|
|
e4cc3104ab | ||
|
|
0c10b4b265 |
@@ -1,17 +1,19 @@
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
#AllowAllArgumentsOnNextLine: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
#AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
#AllowShortLambdasOnASingleLine: Inline
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
@@ -20,6 +22,7 @@ AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
@@ -47,6 +50,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: false
|
||||
IncludeBlocks: Regroup
|
||||
@@ -73,7 +77,7 @@ ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
#SpaceAfterLogicalNot: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
@@ -88,6 +92,6 @@ SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
Standard: Latest
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
42
.github/linters/.markdown-lint.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
###########################
|
||||
###########################
|
||||
## Markdown Linter rules ##
|
||||
###########################
|
||||
###########################
|
||||
|
||||
# Linter rules doc:
|
||||
# - https://github.com/DavidAnson/markdownlint
|
||||
#
|
||||
# Note:
|
||||
# To comment out a single error:
|
||||
# <!-- markdownlint-disable -->
|
||||
# any violations you want
|
||||
# <!-- markdownlint-restore -->
|
||||
#
|
||||
# To run the linter locally:
|
||||
# 1. install the npm package:
|
||||
# `npm install -g markdownlint-cli`
|
||||
# 2. Then run it in the root of the repo with
|
||||
# `markdownlint -c .github\linters\.markdown-lint.yml ./*.md`
|
||||
|
||||
###############
|
||||
# Rules by id #
|
||||
###############
|
||||
MD004: false # Unordered list style
|
||||
MD007:
|
||||
indent: 2 # Unordered list indentation
|
||||
MD013:
|
||||
line_length: 400 # Line length 80 is far to short
|
||||
MD024: false # Allow multiple headings with same content
|
||||
MD026:
|
||||
punctuation: ".,;:!。,;:" # List of not allowed
|
||||
MD029: false # Ordered list item prefix
|
||||
MD033: false # Allow inline HTML
|
||||
MD036: false # Emphasis used instead of a heading
|
||||
MD040: false # Allow ``` blocks in md files with no language specified
|
||||
|
||||
#################
|
||||
# Rules by tags #
|
||||
#################
|
||||
blank_lines: false # Error on blank lines
|
||||
57
.github/workflows/linter.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
###########################
|
||||
###########################
|
||||
## Linter GitHub Actions ##
|
||||
###########################
|
||||
###########################
|
||||
name: Lint Code Base
|
||||
|
||||
#
|
||||
# Documentation:
|
||||
# https://help.github.com/en/articles/workflow-syntax-for-github-actions
|
||||
#
|
||||
|
||||
###################################################
|
||||
# The linter is noisy; we used to run it on push. #
|
||||
###################################################
|
||||
#
|
||||
#on:
|
||||
# pull_request:
|
||||
# branches: [main]
|
||||
|
||||
###############
|
||||
# Set the Job #
|
||||
###############
|
||||
jobs:
|
||||
build:
|
||||
# Name the Job
|
||||
name: Lint Code Base
|
||||
# Set the agent to run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
##################
|
||||
# Load all steps #
|
||||
##################
|
||||
steps:
|
||||
##########################
|
||||
# Checkout the code base #
|
||||
##########################
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
|
||||
################################
|
||||
# Run Linter against code base #
|
||||
################################
|
||||
- name: Lint Code Base
|
||||
uses: github/super-linter@v3
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
DEFAULT_BRANCH: main
|
||||
MARKDOWN_CONFIG_FILE: .markdown-lint.yml
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VALIDATE_EDITORCONFIG: false
|
||||
# The json linter doesn't like JSONC, which we use all over. So just disable it.
|
||||
VALIDATE_JSON: false
|
||||
@@ -14,7 +14,7 @@ The point of doing all this work in public is to ensure that we are holding ours
|
||||
|
||||
The team triages new issues several times a week. During triage, the team uses labels to categorize, manage, and drive the project workflow.
|
||||
|
||||
We employ [a bot engine](https://github.com/microsoft/terminal/blob/master/doc/bot.md) to help us automate common processes within our workflow.
|
||||
We employ [a bot engine](https://github.com/microsoft/terminal/blob/main/doc/bot.md) to help us automate common processes within our workflow.
|
||||
|
||||
We drive the bot by tagging issues with specific labels which cause the bot engine to close issues, merge branches, etc. This bot engine helps us keep the repo clean by automating the process of notifying appropriate parties if/when information/follow-up is needed, and closing stale issues/PRs after reminders have remained unanswered for several days.
|
||||
|
||||
@@ -140,6 +140,13 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and you
|
||||
1. Create & push a feature branch
|
||||
1. Create a [Draft Pull Request (PR)](https://github.blog/2019-02-14-introducing-draft-pull-requests/)
|
||||
1. Work on your changes
|
||||
1. Build and see if it works. Consult [How to build OpenConsole](./doc/building.md) if you have problems.
|
||||
|
||||
### Testing
|
||||
|
||||
Testing is a key component in the development workflow. Both Windows Terminal and Windows Console use TAEF(the Test Authoring and Execution Framework) as the main framework for testing.
|
||||
|
||||
If your changes affect existing test cases, or you're working on brand new features and also the accompanying test cases, see [TAEF](./doc/TAEF.md) for more information about how to validate your work locally.
|
||||
|
||||
### Code Review
|
||||
|
||||
@@ -149,7 +156,7 @@ When you'd like the team to take a look, (even if the work is not yet fully-comp
|
||||
|
||||
### Merge
|
||||
|
||||
Once your code has been reviewed and approved by the requisite number of team members, it will be merged into the master branch. Once merged, your PR will be automatically closed.
|
||||
Once your code has been reviewed and approved by the requisite number of team members, it will be merged into the main branch. Once merged, your PR will be automatically closed.
|
||||
|
||||
---
|
||||
|
||||
|
||||
73
NOTICE.md
@@ -2,7 +2,7 @@
|
||||
Do Not Translate or Localize
|
||||
|
||||
This software incorporates material from third parties. Microsoft makes certain
|
||||
open source code available at http://3rdpartysource.microsoft.com, or you may
|
||||
open source code available at [http://3rdpartysource.microsoft.com](http://3rdpartysource.microsoft.com), or you may
|
||||
send a check or money order for US $5.00, including the product name, the open
|
||||
source component name, and version number, to:
|
||||
|
||||
@@ -20,7 +20,7 @@ General Public License.
|
||||
|
||||
## jsoncpp
|
||||
|
||||
**Source**: https://github.com/open-source-parsers/jsoncpp
|
||||
**Source**: [https://github.com/open-source-parsers/jsoncpp](https://github.com/open-source-parsers/jsoncpp)
|
||||
|
||||
### License
|
||||
|
||||
@@ -48,39 +48,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
## telnetpp
|
||||
|
||||
**Source**: https://github.com/KazDragon/telnetpp
|
||||
|
||||
### License
|
||||
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Matthew Chaplain a.k.a KazDragon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
## chromium/base/numerics
|
||||
|
||||
**Source**: https://github.com/chromium/chromium/tree/master/base/numerics
|
||||
**Source**: [https://github.com/chromium/chromium/tree/master/base/numerics](https://github.com/chromium/chromium/tree/master/base/numerics)
|
||||
|
||||
### License
|
||||
|
||||
@@ -116,7 +86,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## kimwalisch/libpopcnt
|
||||
|
||||
**Source**: https://github.com/kimwalisch/libpopcnt
|
||||
**Source**: [https://github.com/kimwalisch/libpopcnt](https://github.com/kimwalisch/libpopcnt)
|
||||
|
||||
### License
|
||||
|
||||
@@ -152,7 +122,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## dynamic_bitset
|
||||
|
||||
**Source**: https://github.com/pinam45/dynamic_bitset
|
||||
**Source**: [https://github.com/pinam45/dynamic_bitset](https://github.com/pinam45/dynamic_bitset)
|
||||
|
||||
### License
|
||||
|
||||
@@ -181,9 +151,9 @@ SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## {fmt}
|
||||
## \{fmt\}
|
||||
|
||||
**Source**: https://github.com/fmtlib/fmt
|
||||
**Source**: [https://github.com/fmtlib/fmt](https://github.com/fmtlib/fmt)
|
||||
|
||||
### License
|
||||
|
||||
@@ -218,3 +188,32 @@ of this Software are embedded into a machine-executable object form of such
|
||||
source code, you may redistribute such embedded portions in such object form
|
||||
without including the above copyright and permission notices.
|
||||
```
|
||||
|
||||
## interval_tree
|
||||
|
||||
**Source**: [https://github.com/ekg/IntervalTree](https://github.com/ekg/IntervalTree)
|
||||
|
||||
### License
|
||||
|
||||
```
|
||||
Copyright (c) 2011 Erik Garrison
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
<!--<add key="Static Package Dependencies" value="dep\packages" />-->
|
||||
|
||||
<!-- Use our own NuGet Feed -->
|
||||
<add key="Windows Terminal NuGet Feed" value="https://terminalnuget.blob.core.windows.net/feed/index.json" />
|
||||
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/ms/terminal/_packaging/TerminalDependencies/nuget/v3/index.json" />
|
||||
|
||||
<!-- Temporarily? use the feeds from our friends in MUX for Helix test stuff -->
|
||||
<add key="dotnetfeed" value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" />
|
||||
<add key="dnceng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
|
||||
<add key="MUX-Dependencies" value="https://pkgs.dev.azure.com/ms/microsoft-ui-xaml/_packaging/MUX-Dependencies/nuget/v3/index.json" />
|
||||
|
||||
<!-- Internal NuGet feeds that may not be accessible outside Microsoft corporate network -->
|
||||
<!--<add key="TAEF - internal" value="https://microsoft.pkgs.visualstudio.com/DefaultCollection/_packaging/Taef/nuget/v3/index.json" />
|
||||
|
||||
252
OpenConsole.sln
@@ -87,8 +87,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Feature", "src\h
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
|
||||
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalParser.UnitTests", "src\terminal\parser\ut_parser\Parser.UnitTests.vcxproj", "{12144E07-FE63-4D33-9231-748B8D8C3792}"
|
||||
@@ -160,15 +160,11 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalConnection", "src\cascadia\TerminalConnection\TerminalConnection.vcxproj", "{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalCore", "src\cascadia\TerminalCore\lib\TerminalCore-lib.vcxproj", "{CA5CAD1A-ABCD-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalControl", "src\cascadia\TerminalControl\TerminalControl.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
{1CF55140-EF6A-4736-A403-957E4F7430BB} = {1CF55140-EF6A-4736-A403-957E4F7430BB}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63} = {48D21369-3D7B-4431-9967-24E81292CF63}
|
||||
EndProjectSection
|
||||
@@ -178,20 +174,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\casc
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalSettings", "src\cascadia\TerminalSettings\TerminalSettings.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminalShellExt", "src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj", "{F2ED628A-DB22-446F-A081-4CC845B51A2B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalCore", "src\cascadia\UnitTests_TerminalCore\UnitTests.vcxproj", "{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}"
|
||||
@@ -233,17 +226,21 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\lib\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererUia", "src\renderer\uia\lib\uia.vcxproj", "{48D21369-3D7B-4431-9967-24E81292CF63}"
|
||||
@@ -259,6 +256,8 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHostApp", "src\cascadia\LocalTests_TerminalApp\TestHostApp\TestHostApp.vcxproj", "{A021EDFF-45C8-4DC2-BEF7-36E1B3B8CFE8}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {CA5CAD1A-9B68-456A-B13E-C8218070DC42}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BDB237B6-1D1D-400F-84CC-40A58FA59C8E}"
|
||||
@@ -314,8 +313,39 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890} = {84848BFA-931D-42CE-9ADF-01EE54DE7890}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScratchWinRTServer", "src\tools\ScratchWinRTServer\ScratchWinRTServer.vcxproj", "{D46D9547-F085-4645-B8F7-E8CD21559AB4}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF62} = {48D21369-3D7B-4431-9967-24E81292CF62}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScratchIsland", "src\tools\ScratchIsland\ScratchIsland.vcxproj", "{23A1F736-CD19-4196-980F-84BCD50CF783}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4} = {D46D9547-F085-4645-B8F7-E8CD21559AB4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model.Lib", "src\cascadia\TerminalSettingsModel\Microsoft.Terminal.Settings.ModelLib.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model", "src\cascadia\TerminalSettingsModel\dll\Microsoft.Terminal.Settings.Model.vcxproj", "{CA5CAD1A-082C-4476-9F33-94B339494076}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_SettingsModel", "src\cascadia\LocalTests_SettingsModel\SettingsModel.LocalTests.vcxproj", "{CA5CAD1A-9B68-456A-B13E-C8218070DC42}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
AuditMode|Any CPU = AuditMode|Any CPU
|
||||
@@ -1389,35 +1419,6 @@ Global
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x64.Build.0 = AuditMode|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x86Test.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x86Test.Build.0 = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.Build.0 = Release|Win32
|
||||
{F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|Any CPU.ActiveCfg = Release|Win32
|
||||
{F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
|
||||
@@ -1997,6 +1998,90 @@ Global
|
||||
{1588FD7C-241E-4E7D-9113-43735F3E6BAD}.Release|DotNet_x86Test.Build.0 = Release|x86
|
||||
{1588FD7C-241E-4E7D-9113-43735F3E6BAD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1588FD7C-241E-4E7D-9113-43735F3E6BAD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|Any CPU.ActiveCfg = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|Any CPU.Build.0 = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|ARM64.ActiveCfg = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|ARM64.Build.0 = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|DotNet_x64Test.Build.0 = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|DotNet_x86Test.ActiveCfg = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|DotNet_x86Test.Build.0 = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|x64.Build.0 = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.AuditMode|x86.Build.0 = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|ARM64.ActiveCfg = Debug|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|x64.Build.0 = Debug|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Debug|x86.Build.0 = Debug|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|ARM64.ActiveCfg = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|x64.ActiveCfg = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|x64.Build.0 = Release|x64
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|x86.ActiveCfg = Release|Win32
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4}.Release|x86.Build.0 = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|Any CPU.ActiveCfg = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|Any CPU.Build.0 = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|ARM64.ActiveCfg = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|ARM64.Build.0 = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|DotNet_x64Test.Build.0 = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|DotNet_x86Test.ActiveCfg = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|DotNet_x86Test.Build.0 = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|x64.Build.0 = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.AuditMode|x86.Build.0 = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|ARM64.ActiveCfg = Debug|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|x64.Build.0 = Debug|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Debug|x86.Build.0 = Debug|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|ARM64.ActiveCfg = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|x64.ActiveCfg = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|x64.Build.0 = Release|x64
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|x86.ActiveCfg = Release|Win32
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092}.Release|x86.Build.0 = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|Any CPU.ActiveCfg = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|Any CPU.Build.0 = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|ARM64.ActiveCfg = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|ARM64.Build.0 = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|DotNet_x64Test.Build.0 = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|DotNet_x86Test.ActiveCfg = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|DotNet_x86Test.Build.0 = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|x64.Build.0 = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.AuditMode|x86.Build.0 = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|ARM64.ActiveCfg = Debug|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|x64.Build.0 = Debug|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Debug|x86.Build.0 = Debug|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|ARM64.ActiveCfg = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|x64.ActiveCfg = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|x64.Build.0 = Release|x64
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|x86.ActiveCfg = Release|Win32
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783}.Release|x86.Build.0 = Release|Win32
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
@@ -2024,6 +2109,84 @@ Global
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -2073,7 +2236,6 @@ Global
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{F2ED628A-DB22-446F-A081-4CC845B51A2B} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
{EF3E32A7-5FF6-42B4-B6E2-96CD7D033F00} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
|
||||
@@ -2104,7 +2266,13 @@ Global
|
||||
{067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87}
|
||||
{1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{D46D9547-F085-4645-B8F7-E8CD21559AB4} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{06382349-D62A-4C7D-A7D3-9CA817EAE092} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{23A1F736-CD19-4196-980F-84BCD50CF783} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}
|
||||
|
||||
245
README.md
@@ -6,22 +6,26 @@ This repository contains the source code for:
|
||||
* [Windows Terminal Preview](https://aka.ms/terminal-preview)
|
||||
* The Windows console host (`conhost.exe`)
|
||||
* Components shared between the two projects
|
||||
* [ColorTool](https://github.com/Microsoft/Terminal/tree/master/src/tools/ColorTool)
|
||||
* [Sample projects](https://github.com/Microsoft/Terminal/tree/master/samples) that show how to consume the Windows Console APIs
|
||||
* [ColorTool](https://github.com/microsoft/terminal/tree/main/src/tools/ColorTool)
|
||||
* [Sample projects](https://github.com/microsoft/terminal/tree/main/samples)
|
||||
that show how to consume the Windows Console APIs
|
||||
|
||||
Related repositories include:
|
||||
|
||||
* [Windows Terminal Documentation](https://docs.microsoft.com/windows/terminal) ([Repo: Contribute to the docs](https://github.com/MicrosoftDocs/terminal))
|
||||
* [Windows Terminal Documentation](https://docs.microsoft.com/windows/terminal)
|
||||
([Repo: Contribute to the docs](https://github.com/MicrosoftDocs/terminal))
|
||||
* [Console API Documentation](https://github.com/MicrosoftDocs/Console-Docs)
|
||||
* [Cascadia Code Font](https://github.com/Microsoft/Cascadia-Code)
|
||||
|
||||
## Installing and running Windows Terminal
|
||||
|
||||
> 👉 Note: Windows Terminal requires Windows 10 1903 (build 18362) or later
|
||||
> 🔴 Note: Windows Terminal requires Windows 10 1903 (build 18362) or later
|
||||
|
||||
### Microsoft Store [Recommended]
|
||||
|
||||
Install the [Windows Terminal from the Microsoft Store][store-install-link]. This allows you to always be on the latest version when we release new builds with automatic upgrades.
|
||||
Install the [Windows Terminal from the Microsoft Store][store-install-link].
|
||||
This allows you to always be on the latest version when we release new builds
|
||||
with automatic upgrades.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
@@ -29,16 +33,21 @@ This is our preferred method.
|
||||
|
||||
#### Via GitHub
|
||||
|
||||
For users who are unable to install Terminal from the Microsoft Store, Terminal builds can be manually downloaded from this repository's [Releases page](https://github.com/microsoft/terminal/releases).
|
||||
For users who are unable to install Terminal from the Microsoft Store, Terminal
|
||||
builds can be manually downloaded from this repository's [Releases
|
||||
page](https://github.com/microsoft/terminal/releases).
|
||||
|
||||
> ⚠ Note: If you install Terminal manually:
|
||||
> 🔴 Note: If you install Terminal manually:
|
||||
>
|
||||
> * Be sure to install the [Desktop Bridge VC++ v14 Redistributable Package](https://www.microsoft.com/en-us/download/details.aspx?id=53175) otherwise Terminal may not install and/or run and may crash at startup
|
||||
> * Terminal will not auto-update when new builds are released so you will need to regularly install the latest Terminal release to receive all the latest fixes and improvements!
|
||||
> * Terminal will not auto-update when new builds are released so you will need
|
||||
> to regularly install the latest Terminal release to receive all the latest
|
||||
> fixes and improvements!
|
||||
|
||||
#### Via Windows Package Manager CLI (aka winget)
|
||||
|
||||
[winget](https://github.com/microsoft/winget-cli) users can download and install the latest Terminal release by installing the `Microsoft.WindowsTerminal` package:
|
||||
[winget](https://github.com/microsoft/winget-cli) users can download and install
|
||||
the latest Terminal release by installing the `Microsoft.WindowsTerminal`
|
||||
package:
|
||||
|
||||
```powershell
|
||||
winget install --id=Microsoft.WindowsTerminal -e
|
||||
@@ -46,7 +55,8 @@ winget install --id=Microsoft.WindowsTerminal -e
|
||||
|
||||
#### Via Chocolatey (unofficial)
|
||||
|
||||
[Chocolatey](https://chocolatey.org) users can download and install the latest Terminal release by installing the `microsoft-windows-terminal` package:
|
||||
[Chocolatey](https://chocolatey.org) users can download and install the latest
|
||||
Terminal release by installing the `microsoft-windows-terminal` package:
|
||||
|
||||
```powershell
|
||||
choco install microsoft-windows-terminal
|
||||
@@ -58,70 +68,144 @@ To upgrade Windows Terminal using Chocolatey, run the following:
|
||||
choco upgrade microsoft-windows-terminal
|
||||
```
|
||||
|
||||
If you have any issues when installing/upgrading the package please go to the [Windows Terminal package page](https://chocolatey.org/packages/microsoft-windows-terminal) and follow the [Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
|
||||
If you have any issues when installing/upgrading the package please go to the
|
||||
[Windows Terminal package
|
||||
page](https://chocolatey.org/packages/microsoft-windows-terminal) and follow the
|
||||
[Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
|
||||
|
||||
#### Via Scoop (unofficial)
|
||||
|
||||
[Scoop](https://scoop.sh) users can download and install the latest Terminal
|
||||
release by installing the `windows-terminal` package:
|
||||
|
||||
```powershell
|
||||
scoop bucket add extras
|
||||
scoop install windows-terminal
|
||||
```
|
||||
|
||||
To update Windows Terminal using Scoop, run the following:
|
||||
|
||||
```powershell
|
||||
scoop update windows-terminal
|
||||
```
|
||||
|
||||
If you have any issues when installing/updating the package, please search for
|
||||
or report the same on the [issues
|
||||
page](https://github.com/lukesampson/scoop-extras/issues) of Scoop Extras bucket
|
||||
repository.
|
||||
|
||||
---
|
||||
|
||||
## Windows Terminal 2.0 Roadmap
|
||||
|
||||
The plan for delivering Windows Terminal 2.0 [is described here](/doc/terminal-v2-roadmap.md) and will be updated as the project proceeds.
|
||||
The plan for delivering Windows Terminal 2.0 [is described
|
||||
here](/doc/terminal-v2-roadmap.md) and will be updated as the project proceeds.
|
||||
|
||||
## Project Build Status
|
||||
|
||||
Project|Build Status
|
||||
---|---
|
||||
Terminal|[](https://dev.azure.com/ms/Terminal/_build?definitionId=136)
|
||||
ColorTool|
|
||||
Terminal|[](https://dev.azure.com/ms/terminal/_build?definitionId=136)
|
||||
ColorTool|
|
||||
|
||||
---
|
||||
|
||||
## Terminal & Console Overview
|
||||
|
||||
Please take a few minutes to review the overview below before diving into the code:
|
||||
Please take a few minutes to review the overview below before diving into the
|
||||
code:
|
||||
|
||||
### Windows Terminal
|
||||
|
||||
Windows Terminal is a new, modern, feature-rich, productive terminal application for command-line users. It includes many of the features most frequently requested by the Windows command-line community including support for tabs, rich text, globalization, configurability, theming & styling, and more.
|
||||
Windows Terminal is a new, modern, feature-rich, productive terminal application
|
||||
for command-line users. It includes many of the features most frequently
|
||||
requested by the Windows command-line community including support for tabs, rich
|
||||
text, globalization, configurability, theming & styling, and more.
|
||||
|
||||
The Terminal will also need to meet our goals and measures to ensure it remains fast and efficient, and doesn't consume vast amounts of memory or power.
|
||||
The Terminal will also need to meet our goals and measures to ensure it remains
|
||||
fast and efficient, and doesn't consume vast amounts of memory or power.
|
||||
|
||||
### The Windows Console Host
|
||||
|
||||
The Windows Console host, `conhost.exe`, is Windows' original command-line user experience. It also hosts Windows' command-line infrastructure and the Windows Console API server, input engine, rendering engine, user preferences, etc. The console host code in this repository is the actual source from which the `conhost.exe` in Windows itself is built.
|
||||
The Windows Console host, `conhost.exe`, is Windows' original command-line user
|
||||
experience. It also hosts Windows' command-line infrastructure and the Windows
|
||||
Console API server, input engine, rendering engine, user preferences, etc. The
|
||||
console host code in this repository is the actual source from which the
|
||||
`conhost.exe` in Windows itself is built.
|
||||
|
||||
Since taking ownership of the Windows command-line in 2014, the team added several new features to the Console, including background transparency, line-based selection, support for [ANSI / Virtual Terminal sequences](https://en.wikipedia.org/wiki/ANSI_escape_code), [24-bit color](https://devblogs.microsoft.com/commandline/24-bit-color-in-the-windows-console/), a [Pseudoconsole ("ConPTY")](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/), and more.
|
||||
Since taking ownership of the Windows command-line in 2014, the team added
|
||||
several new features to the Console, including background transparency,
|
||||
line-based selection, support for [ANSI / Virtual Terminal
|
||||
sequences](https://en.wikipedia.org/wiki/ANSI_escape_code), [24-bit
|
||||
color](https://devblogs.microsoft.com/commandline/24-bit-color-in-the-windows-console/),
|
||||
a [Pseudoconsole
|
||||
("ConPTY")](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/),
|
||||
and more.
|
||||
|
||||
However, because Windows Console's primary goal is to maintain backward compatibility, we have been unable to add many of the features the community (and the team) have been wanting for the last several years including tabs, unicode text, and emoji.
|
||||
However, because Windows Console's primary goal is to maintain backward
|
||||
compatibility, we have been unable to add many of the features the community
|
||||
(and the team) have been wanting for the last several years including tabs,
|
||||
unicode text, and emoji.
|
||||
|
||||
These limitations led us to create the new Windows Terminal.
|
||||
|
||||
> You can read more about the evolution of the command-line in general, and the Windows command-line specifically in [this accompanying series of blog posts](https://devblogs.microsoft.com/commandline/windows-command-line-backgrounder/) on the Command-Line team's blog.
|
||||
> You can read more about the evolution of the command-line in general, and the
|
||||
> Windows command-line specifically in [this accompanying series of blog
|
||||
> posts](https://devblogs.microsoft.com/commandline/windows-command-line-backgrounder/)
|
||||
> on the Command-Line team's blog.
|
||||
|
||||
### Shared Components
|
||||
|
||||
While overhauling Windows Console, we modernized its codebase considerably, cleanly separating logical entities into modules and classes, introduced some key extensibility points, replaced several old, home-grown collections and containers with safer, more efficient [STL containers](https://docs.microsoft.com/en-us/cpp/standard-library/stl-containers?view=vs-2019), and made the code simpler and safer by using Microsoft's [Windows Implementation Libraries - WIL](https://github.com/Microsoft/wil).
|
||||
While overhauling Windows Console, we modernized its codebase considerably,
|
||||
cleanly separating logical entities into modules and classes, introduced some
|
||||
key extensibility points, replaced several old, home-grown collections and
|
||||
containers with safer, more efficient [STL
|
||||
containers](https://docs.microsoft.com/en-us/cpp/standard-library/stl-containers?view=vs-2019),
|
||||
and made the code simpler and safer by using Microsoft's [Windows Implementation
|
||||
Libraries - WIL](https://github.com/Microsoft/wil).
|
||||
|
||||
This overhaul resulted in several of Console's key components being available for re-use in any terminal implementation on Windows. These components include a new DirectWrite-based text layout and rendering engine, a text buffer capable of storing both UTF-16 and UTF-8, a VT parser/emitter, and more.
|
||||
This overhaul resulted in several of Console's key components being available
|
||||
for re-use in any terminal implementation on Windows. These components include a
|
||||
new DirectWrite-based text layout and rendering engine, a text buffer capable of
|
||||
storing both UTF-16 and UTF-8, a VT parser/emitter, and more.
|
||||
|
||||
### Creating the new Windows Terminal
|
||||
|
||||
When we started planning the new Windows Terminal application, we explored and evaluated several approaches and technology stacks. We ultimately decided that our goals would be best met by continuing our investment in our C++ codebase, which would allow us to reuse several of the aforementioned modernized components in both the existing Console and the new Terminal. Further, we realized that this would allow us to build much of the Terminal's core itself as a reusable UI control that others can incorporate into their own applications.
|
||||
When we started planning the new Windows Terminal application, we explored and
|
||||
evaluated several approaches and technology stacks. We ultimately decided that
|
||||
our goals would be best met by continuing our investment in our C++ codebase,
|
||||
which would allow us to reuse several of the aforementioned modernized
|
||||
components in both the existing Console and the new Terminal. Further, we
|
||||
realized that this would allow us to build much of the Terminal's core itself as
|
||||
a reusable UI control that others can incorporate into their own applications.
|
||||
|
||||
The result of this work is contained within this repo and delivered as the Windows Terminal application you can download from the Microsoft Store, or [directly from this repo's releases](https://github.com/microsoft/terminal/releases).
|
||||
The result of this work is contained within this repo and delivered as the
|
||||
Windows Terminal application you can download from the Microsoft Store, or
|
||||
[directly from this repo's
|
||||
releases](https://github.com/microsoft/terminal/releases).
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
For more information about Windows Terminal, you may find some of these resources useful and interesting:
|
||||
For more information about Windows Terminal, you may find some of these
|
||||
resources useful and interesting:
|
||||
|
||||
* [Command-Line Blog](https://devblogs.microsoft.com/commandline)
|
||||
* [Command-Line Backgrounder Blog Series](https://devblogs.microsoft.com/commandline/windows-command-line-backgrounder/)
|
||||
* Windows Terminal Launch: [Terminal "Sizzle Video"](https://www.youtube.com/watch?v=8gw0rXPMMPE&list=PLEHMQNlPj-Jzh9DkNpqipDGCZZuOwrQwR&index=2&t=0s)
|
||||
* Windows Terminal Launch: [Build 2019 Session](https://www.youtube.com/watch?v=KMudkRcwjCw)
|
||||
* Run As Radio: [Show 645 - Windows Terminal with Richard Turner](http://www.runasradio.com/Shows/Show/645)
|
||||
* Azure Devops Podcast: [Episode 54 - Kayla Cinnamon and Rich Turner on DevOps on the Windows Terminal](http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54)
|
||||
* Microsoft Ignite 2019 Session: [The Modern Windows Command Line: Windows Terminal - BRK3321](https://myignite.techcommunity.microsoft.com/sessions/81329?source=sessions)
|
||||
* [Command-Line Backgrounder Blog
|
||||
Series](https://devblogs.microsoft.com/commandline/windows-command-line-backgrounder/)
|
||||
* Windows Terminal Launch: [Terminal "Sizzle
|
||||
Video"](https://www.youtube.com/watch?v=8gw0rXPMMPE&list=PLEHMQNlPj-Jzh9DkNpqipDGCZZuOwrQwR&index=2&t=0s)
|
||||
* Windows Terminal Launch: [Build 2019
|
||||
Session](https://www.youtube.com/watch?v=KMudkRcwjCw)
|
||||
* Run As Radio: [Show 645 - Windows Terminal with Richard
|
||||
Turner](http://www.runasradio.com/Shows/Show/645)
|
||||
* Azure Devops Podcast: [Episode 54 - Kayla Cinnamon and Rich Turner on DevOps
|
||||
on the Windows
|
||||
Terminal](http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54)
|
||||
* Microsoft Ignite 2019 Session: [The Modern Windows Command Line: Windows
|
||||
Terminal -
|
||||
BRK3321](https://myignite.techcommunity.microsoft.com/sessions/81329?source=sessions)
|
||||
|
||||
---
|
||||
|
||||
@@ -131,48 +215,72 @@ For more information about Windows Terminal, you may find some of these resource
|
||||
|
||||
Cause: You're launching the incorrect solution in Visual Studio.
|
||||
|
||||
Solution: Make sure you're building & deploying the `CascadiaPackage` project in Visual Studio.
|
||||
Solution: Make sure you're building & deploying the `CascadiaPackage` project in
|
||||
Visual Studio.
|
||||
|
||||
> ⚠ Note: `OpenConsole.exe` is just a locally-built `conhost.exe`, the classic Windows Console that hosts Windows' command-line infrastructure. OpenConsole is used by Windows Terminal to connect to and communicate with command-line applications (via [ConPty](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/)).
|
||||
> ⚠ Note: `OpenConsole.exe` is just a locally-built `conhost.exe`, the classic
|
||||
> Windows Console that hosts Windows' command-line infrastructure. OpenConsole
|
||||
> is used by Windows Terminal to connect to and communicate with command-line
|
||||
> applications (via
|
||||
> [ConPty](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/)).
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
All project documentation is located at aka.ms/terminal-docs. If you would like to contribute to the documentation, please submit a pull request on the [Windows Terminal Documentation repo](https://github.com/MicrosoftDocs/terminal).
|
||||
All project documentation is located at aka.ms/terminal-docs. If you would like
|
||||
to contribute to the documentation, please submit a pull request on the [Windows
|
||||
Terminal Documentation repo](https://github.com/MicrosoftDocs/terminal).
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
We are excited to work alongside you, our amazing community, to build and enhance Windows Terminal\!
|
||||
We are excited to work alongside you, our amazing community, to build and
|
||||
enhance Windows Terminal\!
|
||||
|
||||
***BEFORE you start work on a feature/fix***, please read & follow our [Contributor's Guide](https://github.com/microsoft/terminal/blob/master/CONTRIBUTING.md) to help avoid any wasted or duplicate effort.
|
||||
***BEFORE you start work on a feature/fix***, please read & follow our
|
||||
[Contributor's
|
||||
Guide](https://github.com/microsoft/terminal/blob/main/CONTRIBUTING.md) to
|
||||
help avoid any wasted or duplicate effort.
|
||||
|
||||
## Communicating with the Team
|
||||
|
||||
The easiest way to communicate with the team is via GitHub issues.
|
||||
|
||||
Please file new issues, feature requests and suggestions, but **DO search for similar open/closed pre-existing issues before creating a new issue.**
|
||||
Please file new issues, feature requests and suggestions, but **DO search for
|
||||
similar open/closed pre-existing issues before creating a new issue.**
|
||||
|
||||
If you would like to ask a question that you feel doesn't warrant an issue (yet), please reach out to us via Twitter:
|
||||
If you would like to ask a question that you feel doesn't warrant an issue
|
||||
(yet), please reach out to us via Twitter:
|
||||
|
||||
* Kayla Cinnamon, Program Manager: [@cinnamon\_msft](https://twitter.com/cinnamon_msft)
|
||||
* Kayla Cinnamon, Program Manager:
|
||||
[@cinnamon\_msft](https://twitter.com/cinnamon_msft)
|
||||
* Dustin Howett, Engineering Lead: [@dhowett](https://twitter.com/DHowett)
|
||||
* Michael Niksa, Senior Developer: [@michaelniksa](https://twitter.com/MichaelNiksa)
|
||||
* Michael Niksa, Senior Developer:
|
||||
[@michaelniksa](https://twitter.com/MichaelNiksa)
|
||||
* Mike Griese, Developer: [@zadjii](https://twitter.com/zadjii)
|
||||
* Carlos Zamora, Developer: [@cazamor_msft](https://twitter.com/cazamor_msft)
|
||||
* Leon Liang, Developer: [@leonmsft](https://twitter.com/leonmsft)
|
||||
* Pankaj Bhojwani, Developer
|
||||
|
||||
## Developer Guidance
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* You must be running Windows 1903 (build >= 10.0.18362.0) or later to run Windows Terminal
|
||||
* You must [enable Developer Mode in the Windows Settings app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) to locally install and run Windows Terminal
|
||||
* You must have the [Windows 10 1903 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) installed
|
||||
* You must have at least [VS 2019](https://visualstudio.microsoft.com/downloads/) installed
|
||||
* You must install the following Workloads via the VS Installer. Note: Opening the solution in VS 2019 will [prompt you to install missing components automatically](https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/):
|
||||
* You must be running Windows 1903 (build >= 10.0.18362.0) or later to run
|
||||
Windows Terminal
|
||||
* You must [enable Developer Mode in the Windows Settings
|
||||
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
|
||||
to locally install and run Windows Terminal
|
||||
* You must have the [Windows 10 1903
|
||||
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
|
||||
installed
|
||||
* You must have at least [VS
|
||||
2019](https://visualstudio.microsoft.com/downloads/) installed
|
||||
* You must install the following Workloads via the VS Installer. Note: Opening
|
||||
the solution in VS 2019 will [prompt you to install missing components
|
||||
automatically](https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/):
|
||||
* Desktop Development with C++
|
||||
* Universal Windows Platform Development
|
||||
* **The following Individual Components**
|
||||
@@ -180,13 +288,17 @@ If you would like to ask a question that you feel doesn't warrant an issue (yet)
|
||||
|
||||
## Building the Code
|
||||
|
||||
This repository uses [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) for some of its dependencies. To make sure submodules are restored or updated, be sure to run the following prior to building:
|
||||
This repository uses [git
|
||||
submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) for some of its
|
||||
dependencies. To make sure submodules are restored or updated, be sure to run
|
||||
the following prior to building:
|
||||
|
||||
```shell
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
OpenConsole.sln may be built from within Visual Studio or from the command-line using a set of convenience scripts & tools in the **/tools** directory:
|
||||
OpenConsole.sln may be built from within Visual Studio or from the command-line
|
||||
using a set of convenience scripts & tools in the **/tools** directory:
|
||||
|
||||
### Building in PowerShell
|
||||
|
||||
@@ -205,31 +317,42 @@ bcz
|
||||
|
||||
## Running & Debugging
|
||||
|
||||
To debug the Windows Terminal in VS, right click on `CascadiaPackage` (in the Solution Explorer) and go to properties. In the Debug menu, change "Application process" and "Background task process" to "Native Only".
|
||||
To debug the Windows Terminal in VS, right click on `CascadiaPackage` (in the
|
||||
Solution Explorer) and go to properties. In the Debug menu, change "Application
|
||||
process" and "Background task process" to "Native Only".
|
||||
|
||||
You should then be able to build & debug the Terminal project by hitting <kbd>F5</kbd>.
|
||||
You should then be able to build & debug the Terminal project by hitting
|
||||
<kbd>F5</kbd>.
|
||||
|
||||
> 👉 You will _not_ be able to launch the Terminal directly by running the WindowsTerminal.exe. For more details on why, see [#926](https://github.com/microsoft/terminal/issues/926), [#4043](https://github.com/microsoft/terminal/issues/4043)
|
||||
> 👉 You will _not_ be able to launch the Terminal directly by running the
|
||||
> WindowsTerminal.exe. For more details on why, see
|
||||
> [#926](https://github.com/microsoft/terminal/issues/926),
|
||||
> [#4043](https://github.com/microsoft/terminal/issues/4043)
|
||||
|
||||
### Coding Guidance
|
||||
|
||||
Please review these brief docs below about our coding practices.
|
||||
|
||||
> 👉 If you find something missing from these docs, feel free to contribute to any of our documentation files anywhere in the repository (or write some new ones!)
|
||||
> 👉 If you find something missing from these docs, feel free to contribute to
|
||||
> any of our documentation files anywhere in the repository (or write some new
|
||||
> ones!)
|
||||
|
||||
This is a work in progress as we learn what we'll need to provide people in order to be effective contributors to our project.
|
||||
This is a work in progress as we learn what we'll need to provide people in
|
||||
order to be effective contributors to our project.
|
||||
|
||||
* [Coding Style](https://github.com/Microsoft/Terminal/blob/master/doc/STYLE.md)
|
||||
* [Code Organization](https://github.com/Microsoft/Terminal/blob/master/doc/ORGANIZATION.md)
|
||||
* [Exceptions in our legacy codebase](https://github.com/Microsoft/Terminal/blob/master/doc/EXCEPTIONS.md)
|
||||
* [Helpful smart pointers and macros for interfacing with Windows in WIL](https://github.com/Microsoft/Terminal/blob/master/doc/WIL.md)
|
||||
* [Coding Style](https://github.com/microsoft/terminal/blob/main/doc/STYLE.md)
|
||||
* [Code Organization](https://github.com/microsoft/terminal/blob/main/doc/ORGANIZATION.md)
|
||||
* [Exceptions in our legacy codebase](https://github.com/microsoft/terminal/blob/main/doc/EXCEPTIONS.md)
|
||||
* [Helpful smart pointers and macros for interfacing with Windows in WIL](https://github.com/microsoft/terminal/blob/main/doc/WIL.md)
|
||||
|
||||
---
|
||||
|
||||
# Code of Conduct
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code].
|
||||
For more information see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments.
|
||||
This project has adopted the [Microsoft Open Source Code of
|
||||
Conduct][conduct-code]. For more information see the [Code of Conduct
|
||||
FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any
|
||||
additional questions or comments.
|
||||
|
||||
[conduct-code]: https://opensource.microsoft.com/codeofconduct/
|
||||
[conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
|
||||
|
||||
17
SUPPORT.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses [GitHub issues][gh-issue] to [track bugs][gh-bug] and [feature requests][gh-feature]. Please search the existing issues before filing new issues to avoid duplicates. For new topics, file your bug or feature request as a new issue.
|
||||
|
||||
For help and questions about using this project, please look at the [docs site for Windows Terminal][docs] and our [Contributor's Guide][contributor] if you want to work on Windows Terminal.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for Windows Terminal is limited to the resources listed above.
|
||||
|
||||
[gh-issue]: https://github.com/microsoft/terminal/issues/new/choose
|
||||
[gh-bug]: https://github.com/microsoft/terminal/issues/new?assignees=&labels=Issue-Bug&template=bug_report.md&title=
|
||||
[gh-feature]: https://github.com/microsoft/terminal/issues/new?assignees=&labels=Issue-Feature&template=Feature_Request.md&title=
|
||||
[docs]: https://docs.microsoft.com/windows/terminal
|
||||
[contributor]: https://github.com/microsoft/terminal/blob/main/CONTRIBUTING.md
|
||||
32
build/Helix/AzurePipelinesHelperScripts.ps1
Normal file
@@ -0,0 +1,32 @@
|
||||
function GetAzureDevOpsBaseUri
|
||||
{
|
||||
Param(
|
||||
[string]$CollectionUri,
|
||||
[string]$TeamProject
|
||||
)
|
||||
|
||||
return $CollectionUri + $TeamProject
|
||||
}
|
||||
|
||||
function GetQueryTestRunsUri
|
||||
{
|
||||
Param(
|
||||
[string]$CollectionUri,
|
||||
[string]$TeamProject,
|
||||
[string]$BuildUri,
|
||||
[switch]$IncludeRunDetails
|
||||
)
|
||||
|
||||
if ($IncludeRunDetails)
|
||||
{
|
||||
$includeRunDetailsParameter = "&includeRunDetails=true"
|
||||
}
|
||||
else
|
||||
{
|
||||
$includeRunDetailsParameter = ""
|
||||
}
|
||||
|
||||
$baseUri = GetAzureDevOpsBaseUri -CollectionUri $CollectionUri -TeamProject $TeamProject
|
||||
$queryUri = "$baseUri/_apis/test/runs?buildUri=$BuildUri$includeRunDetailsParameter&api-version=5.0"
|
||||
return $queryUri
|
||||
}
|
||||
28
build/Helix/ConvertWttLogToXUnit.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
Param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttInputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttSingleRerunInputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttMultipleRerunInputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$XUnitOutputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$TestNamePrefix
|
||||
)
|
||||
|
||||
# Ideally these would be passed as parameters to the script. However ps makes it difficult to deal with string literals containing '&', so we just
|
||||
# read the values directly from the environment variables
|
||||
$helixResultsContainerUri = $Env:HELIX_RESULTS_CONTAINER_URI
|
||||
$helixResultsContainerRsas = $Env:HELIX_RESULTS_CONTAINER_RSAS
|
||||
|
||||
$rerunPassesRequiredToAvoidFailure = $env:rerunPassesRequiredToAvoidFailure
|
||||
|
||||
Add-Type -Language CSharp -ReferencedAssemblies System.Xml,System.Xml.Linq,System.Runtime.Serialization,System.Runtime.Serialization.Json (Get-Content $PSScriptRoot\HelixTestHelpers.cs -Raw)
|
||||
|
||||
$testResultParser = [HelixTestHelpers.TestResultParser]::new($TestNamePrefix, $helixResultsContainerUri, $helixResultsContainerRsas)
|
||||
$testResultParser.ConvertWttLogToXUnitLog($WttInputPath, $WttSingleRerunInputPath, $WttMultipleRerunInputPath, $XUnitOutputPath, $rerunPassesRequiredToAvoidFailure)
|
||||
112
build/Helix/EnsureMachineState.ps1
Normal file
@@ -0,0 +1,112 @@
|
||||
$scriptDirectory = $script:MyInvocation.MyCommand.Path | Split-Path -Parent
|
||||
|
||||
# List all processes to aid debugging:
|
||||
Write-Host "All processes running:"
|
||||
Get-Process
|
||||
|
||||
tasklist /svc
|
||||
|
||||
# Add this test directory as an exclusion for Windows Defender
|
||||
Write-Host "Add $scriptDirectory as Exclusion Path"
|
||||
Add-MpPreference -ExclusionPath $scriptDirectory
|
||||
Write-Host "Add $($env:HELIX_CORRELATION_PAYLOAD) as Exclusion Path"
|
||||
Add-MpPreference -ExclusionPath $env:HELIX_CORRELATION_PAYLOAD
|
||||
Get-MpPreference
|
||||
Get-MpComputerStatus
|
||||
|
||||
|
||||
# Minimize all windows:
|
||||
$shell = New-Object -ComObject "Shell.Application"
|
||||
$shell.minimizeall()
|
||||
|
||||
# Kill any instances of Windows Security Alert:
|
||||
$windowTitleToMatch = "*Windows Security Alert*"
|
||||
$procs = Get-Process | Where {$_.MainWindowTitle -like "*Windows Security Alert*"}
|
||||
foreach ($proc in $procs)
|
||||
{
|
||||
Write-Host "Found process with '$windowTitleToMatch' title: $proc"
|
||||
$proc.Kill();
|
||||
}
|
||||
|
||||
# Kill processes by name that are known to interfere with our tests:
|
||||
$processNamesToStop = @("Microsoft.Photos", "WinStore.App", "SkypeApp", "SkypeBackgroundHost", "OneDriveSetup", "OneDrive")
|
||||
foreach($procName in $processNamesToStop)
|
||||
{
|
||||
Write-Host "Attempting to kill $procName if it is running"
|
||||
Stop-Process -ProcessName $procName -Verbose -ErrorAction Ignore
|
||||
}
|
||||
Write-Host "All processes running after attempting to kill unwanted processes:"
|
||||
Get-Process
|
||||
|
||||
tasklist /svc
|
||||
|
||||
$platform = $env:testbuildplatform
|
||||
if(!$platform)
|
||||
{
|
||||
$platform = "x86"
|
||||
}
|
||||
|
||||
function UninstallApps {
|
||||
Param([string[]]$appsToUninstall)
|
||||
|
||||
foreach($pkgName in $appsToUninstall)
|
||||
{
|
||||
foreach($pkg in (Get-AppxPackage $pkgName).PackageFullName)
|
||||
{
|
||||
Write-Output "Removing: $pkg"
|
||||
Remove-AppxPackage $pkg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UninstallTestApps {
|
||||
Param([string[]]$appsToUninstall)
|
||||
|
||||
foreach($pkgName in $appsToUninstall)
|
||||
{
|
||||
foreach($pkg in (Get-AppxPackage $pkgName).PackageFullName)
|
||||
{
|
||||
Write-Output "Removing: $pkg"
|
||||
Remove-AppxPackage $pkg
|
||||
}
|
||||
|
||||
# Sometimes an app can get into a state where it is no longer returned by Get-AppxPackage, but it is still present
|
||||
# which prevents other versions of the app from being installed.
|
||||
# To handle this, we can directly call Remove-AppxPackage against the full name of the package. However, without
|
||||
# Get-AppxPackage to find the PackageFullName, we just have to manually construct the name.
|
||||
$packageFullName = "$($pkgName)_1.0.0.0_$($platform)__8wekyb3d8bbwe"
|
||||
Write-Host "Removing $packageFullName if installed"
|
||||
Remove-AppPackage $packageFullName -ErrorVariable appxerror -ErrorAction SilentlyContinue
|
||||
if($appxerror)
|
||||
{
|
||||
foreach($error in $appxerror)
|
||||
{
|
||||
# In most cases, Remove-AppPackage will fail due to the package not being found. Don't treat this as an error.
|
||||
if(!($error.Exception.Message -match "0x80073CF1"))
|
||||
{
|
||||
Write-Error $error
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Successfully removed $packageFullName"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Uninstall AppX packages that are known to cause issues with our tests"
|
||||
UninstallApps("*Skype*", "*Windows.Photos*")
|
||||
|
||||
Write-Host "Uninstall any of our test apps that may have been left over from previous test runs"
|
||||
UninstallTestApps("NugetPackageTestApp", "NugetPackageTestAppCX", "IXMPTestApp", "MUXControlsTestApp")
|
||||
|
||||
Write-Host "Uninstall MUX Framework package that may have been left over from previous test runs"
|
||||
# We don't want to uninstall all versions of the MUX Framework package, as there may be other apps preinstalled on the system
|
||||
# that depend on it. We only uninstall the Framework package that corresponds to the version of MUX that we are testing.
|
||||
[xml]$versionData = (Get-Content "version.props")
|
||||
$versionMajor = $versionData.GetElementsByTagName("MUXVersionMajor").'#text'
|
||||
$versionMinor = $versionData.GetElementsByTagName("MUXVersionMinor").'#text'
|
||||
UninstallApps("Microsoft.UI.Xaml.$versionMajor.$versionMinor")
|
||||
|
||||
Get-Process
|
||||
336
build/Helix/GenerateTestProjFile.ps1
Normal file
@@ -0,0 +1,336 @@
|
||||
[CmdLetBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$TestFile,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OutputProjFile,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$JobTestSuiteName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$TaefPath,
|
||||
|
||||
[string]$TaefQuery
|
||||
)
|
||||
|
||||
Class TestCollection
|
||||
{
|
||||
[string]$Name
|
||||
[string]$SetupMethodName
|
||||
[string]$TeardownMethodName
|
||||
[System.Collections.Generic.Dictionary[string, string]]$Properties
|
||||
|
||||
TestCollection()
|
||||
{
|
||||
if ($this.GetType() -eq [TestCollection])
|
||||
{
|
||||
throw "This class should never be instantiated directly; it should only be derived from."
|
||||
}
|
||||
}
|
||||
|
||||
TestCollection([string]$name)
|
||||
{
|
||||
$this.Init($name)
|
||||
}
|
||||
|
||||
hidden Init([string]$name)
|
||||
{
|
||||
$this.Name = $name
|
||||
$this.Properties = @{}
|
||||
}
|
||||
}
|
||||
|
||||
Class Test : TestCollection
|
||||
{
|
||||
Test([string]$name)
|
||||
{
|
||||
$this.Init($name)
|
||||
}
|
||||
}
|
||||
|
||||
Class TestClass : TestCollection
|
||||
{
|
||||
[System.Collections.Generic.List[Test]]$Tests
|
||||
|
||||
TestClass([string]$name)
|
||||
{
|
||||
$this.Init($name)
|
||||
$this.Tests = @{}
|
||||
}
|
||||
}
|
||||
|
||||
Class TestModule : TestCollection
|
||||
{
|
||||
[System.Collections.Generic.List[TestClass]]$TestClasses
|
||||
|
||||
TestModule([string]$name)
|
||||
{
|
||||
$this.Init($name)
|
||||
$this.TestClasses = @{}
|
||||
}
|
||||
}
|
||||
|
||||
function Parse-TestInfo([string]$taefOutput)
|
||||
{
|
||||
enum LineType
|
||||
{
|
||||
None
|
||||
TestModule
|
||||
TestClass
|
||||
Test
|
||||
Setup
|
||||
Teardown
|
||||
Property
|
||||
}
|
||||
|
||||
[string]$testModuleIndentation = " "
|
||||
[string]$testClassIndentation = " "
|
||||
[string]$testIndentation = " "
|
||||
[string]$setupBeginning = "Setup: "
|
||||
[string]$teardownBeginning = "Teardown: "
|
||||
[string]$propertyBeginning = "Property["
|
||||
|
||||
function Get-LineType([string]$line)
|
||||
{
|
||||
if ($line.Contains($setupBeginning))
|
||||
{
|
||||
return [LineType]::Setup;
|
||||
}
|
||||
elseif ($line.Contains($teardownBeginning))
|
||||
{
|
||||
return [LineType]::Teardown;
|
||||
}
|
||||
elseif ($line.Contains($propertyBeginning))
|
||||
{
|
||||
return [LineType]::Property;
|
||||
}
|
||||
elseif ($line.StartsWith($testModuleIndentation) -and -not $line.StartsWith("$testModuleIndentation "))
|
||||
{
|
||||
return [LineType]::TestModule;
|
||||
}
|
||||
elseif ($line.StartsWith($testClassIndentation) -and -not $line.StartsWith("$testClassIndentation "))
|
||||
{
|
||||
return [LineType]::TestClass;
|
||||
}
|
||||
elseif ($line.StartsWith($testIndentation) -and -not $line.StartsWith("$testIndentation "))
|
||||
{
|
||||
return [LineType]::Test;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [LineType]::None;
|
||||
}
|
||||
}
|
||||
|
||||
[string[]]$lines = $taefOutput.Split(@([Environment]::NewLine, "`n"), [StringSplitOptions]::RemoveEmptyEntries)
|
||||
[System.Collections.Generic.List[TestModule]]$testModules = @()
|
||||
|
||||
[TestModule]$currentTestModule = $null
|
||||
[TestClass]$currentTestClass = $null
|
||||
[Test]$currentTest = $null
|
||||
|
||||
[TestCollection]$lastTestCollection = $null
|
||||
|
||||
foreach ($rawLine in $lines)
|
||||
{
|
||||
[LineType]$lineType = (Get-LineType $rawLine)
|
||||
|
||||
# We don't need the whitespace around the line anymore, so we'll discard it to make things easier.
|
||||
[string]$line = $rawLine.Trim()
|
||||
|
||||
if ($lineType -eq [LineType]::TestModule)
|
||||
{
|
||||
if ($currentTest -ne $null -and $currentTestClass -ne $null)
|
||||
{
|
||||
$currentTestClass.Tests.Add($currentTest)
|
||||
}
|
||||
|
||||
if ($currentTestClass -ne $null -and $currentTestModule -ne $null)
|
||||
{
|
||||
$currentTestModule.TestClasses.Add($currentTestClass)
|
||||
}
|
||||
|
||||
if ($currentTestModule -ne $null)
|
||||
{
|
||||
$testModules.Add($currentTestModule)
|
||||
}
|
||||
|
||||
$currentTestModule = [TestModule]::new($line)
|
||||
$currentTestClass = $null
|
||||
$currentTest = $null
|
||||
$lastTestCollection = $currentTestModule
|
||||
}
|
||||
elseif ($lineType -eq [LineType]::TestClass)
|
||||
{
|
||||
if ($currentTest -ne $null -and $currentTestClass -ne $null)
|
||||
{
|
||||
$currentTestClass.Tests.Add($currentTest)
|
||||
}
|
||||
|
||||
if ($currentTestClass -ne $null -and $currentTestModule -ne $null)
|
||||
{
|
||||
$currentTestModule.TestClasses.Add($currentTestClass)
|
||||
}
|
||||
|
||||
$currentTestClass = [TestClass]::new($line)
|
||||
$currentTest = $null
|
||||
$lastTestCollection = $currentTestClass
|
||||
}
|
||||
elseif ($lineType -eq [LineType]::Test)
|
||||
{
|
||||
if ($currentTest -ne $null -and $currentTestClass -ne $null)
|
||||
{
|
||||
$currentTestClass.Tests.Add($currentTest)
|
||||
}
|
||||
|
||||
$currentTest = [Test]::new($line)
|
||||
$lastTestCollection = $currentTest
|
||||
}
|
||||
elseif ($lineType -eq [LineType]::Setup)
|
||||
{
|
||||
if ($lastTestCollection -ne $null)
|
||||
{
|
||||
$lastTestCollection.SetupMethodName = $line.Replace($setupBeginning, "")
|
||||
}
|
||||
}
|
||||
elseif ($lineType -eq [LineType]::Teardown)
|
||||
{
|
||||
if ($lastTestCollection -ne $null)
|
||||
{
|
||||
$lastTestCollection.TeardownMethodName = $line.Replace($teardownBeginning, "")
|
||||
}
|
||||
}
|
||||
elseif ($lineType -eq [LineType]::Property)
|
||||
{
|
||||
if ($lastTestCollection -ne $null)
|
||||
{
|
||||
foreach ($match in [Regex]::Matches($line, "Property\[(.*)\]\s+=\s+(.*)"))
|
||||
{
|
||||
[string]$propertyKey = $match.Groups[1].Value;
|
||||
[string]$propertyValue = $match.Groups[2].Value;
|
||||
$lastTestCollection.Properties.Add($propertyKey, $propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($currentTest -ne $null -and $currentTestClass -ne $null)
|
||||
{
|
||||
$currentTestClass.Tests.Add($currentTest)
|
||||
}
|
||||
|
||||
if ($currentTestClass -ne $null -and $currentTestModule -ne $null)
|
||||
{
|
||||
$currentTestModule.TestClasses.Add($currentTestClass)
|
||||
}
|
||||
|
||||
if ($currentTestModule -ne $null)
|
||||
{
|
||||
$testModules.Add($currentTestModule)
|
||||
}
|
||||
|
||||
return $testModules
|
||||
}
|
||||
|
||||
Write-Verbose "TaefQuery = $TaefQuery"
|
||||
|
||||
$TaefSelectQuery = ""
|
||||
$TaefQueryToAppend = ""
|
||||
if($TaefQuery)
|
||||
{
|
||||
$TaefSelectQuery = "/select:`"$TaefQuery`""
|
||||
$TaefQueryToAppend = " and $TaefQuery"
|
||||
}
|
||||
Write-Verbose "TaefSelectQuery = $TaefSelectQuery"
|
||||
|
||||
|
||||
$taefExe = "$TaefPath\te.exe"
|
||||
[string]$taefOutput = & "$taefExe" /listproperties $TaefSelectQuery $TestFile | Out-String
|
||||
|
||||
[System.Collections.Generic.List[TestModule]]$testModules = (Parse-TestInfo $taefOutput)
|
||||
|
||||
$projFileContent = @"
|
||||
<Project>
|
||||
<ItemGroup>
|
||||
"@
|
||||
|
||||
foreach ($testModule in $testModules)
|
||||
{
|
||||
foreach ($testClass in $testModules.TestClasses)
|
||||
{
|
||||
Write-Host "Generating Helix work item for test class $($testClass.Name)..."
|
||||
[System.Collections.Generic.List[string]]$testSuiteNames = @()
|
||||
|
||||
$testSuiteExists = $false
|
||||
$suitelessTestExists = $false
|
||||
|
||||
foreach ($test in $testClass.Tests)
|
||||
{
|
||||
# A test method inherits its 'TestSuite' property from its TestClass
|
||||
if (!$test.Properties.ContainsKey("TestSuite") -and $testClass.Properties.ContainsKey("TestSuite"))
|
||||
{
|
||||
$test.Properties["TestSuite"] = $testClass.Properties["TestSuite"]
|
||||
}
|
||||
|
||||
if ($test.Properties.ContainsKey("TestSuite"))
|
||||
{
|
||||
[string]$testSuite = $test.Properties["TestSuite"]
|
||||
|
||||
if (-not $testSuiteNames.Contains($testSuite))
|
||||
{
|
||||
Write-Host " Found test suite $testSuite. Generating Helix work item for it as well."
|
||||
$testSuiteNames.Add($testSuite)
|
||||
}
|
||||
|
||||
$testSuiteExists = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$suitelessTestExists = $true
|
||||
}
|
||||
}
|
||||
|
||||
$testClassSelectPattern = "$($testClass.Name).*"
|
||||
if($testClass.Name.Contains("::"))
|
||||
{
|
||||
$testClassSelectPattern = "$($testClass.Name)::*"
|
||||
}
|
||||
$testNameQuery= "(@Name='$testClassSelectPattern')"
|
||||
|
||||
$workItemName = $testClass.Name
|
||||
# Native tests use '::' as a separator, which is not valid for workItem names.
|
||||
$workItemName = $workItemName -replace "::", "-"
|
||||
|
||||
if ($suitelessTestExists)
|
||||
{
|
||||
$projFileContent += @"
|
||||
|
||||
<HelixWorkItem Include="$($workItemName)" Condition="'`$(TestSuite)'=='$($JobTestSuiteName)'">
|
||||
<Timeout>00:30:00</Timeout>
|
||||
<Command>call %HELIX_CORRELATION_PAYLOAD%\runtests.cmd /select:"(@Name='$($testClass.Name)*'$(if ($testSuiteExists) { "and not @TestSuite='*'" }))$($TaefQueryToAppend)"</Command>
|
||||
</HelixWorkItem>
|
||||
"@
|
||||
}
|
||||
|
||||
foreach ($testSuiteName in $testSuiteNames)
|
||||
{
|
||||
$projFileContent += @"
|
||||
|
||||
<HelixWorkItem Include="$($workItemName)-$testSuiteName" Condition="'`$(TestSuite)'=='$($JobTestSuiteName)'">
|
||||
<Timeout>00:30:00</Timeout>
|
||||
<Command>call %HELIX_CORRELATION_PAYLOAD%\runtests.cmd /select:"(@Name='$($testClass.Name)*' and @TestSuite='$testSuiteName')$($TaefQueryToAppend)"</Command>
|
||||
</HelixWorkItem>
|
||||
"@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$projFileContent += @"
|
||||
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
"@
|
||||
|
||||
Set-Content $OutputProjFile $projFileContent -NoNewline -Encoding UTF8
|
||||
669
build/Helix/HelixTestHelpers.cs
Normal file
@@ -0,0 +1,669 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace HelixTestHelpers
|
||||
{
|
||||
public class TestResult
|
||||
{
|
||||
public TestResult()
|
||||
{
|
||||
Screenshots = new List<string>();
|
||||
RerunResults = new List<TestResult>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string SourceWttFile { get; set; }
|
||||
public bool Passed { get; set; }
|
||||
public bool CleanupPassed { get; set; }
|
||||
public TimeSpan ExecutionTime { get; set; }
|
||||
public string Details { get; set; }
|
||||
|
||||
public List<string> Screenshots { get; private set; }
|
||||
public List<TestResult> RerunResults { get; private set; }
|
||||
|
||||
// Returns true if the test pass rate is sufficient to avoid being counted as a failure.
|
||||
public bool PassedOrUnreliable(int requiredNumberOfPasses)
|
||||
{
|
||||
if(Passed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(RerunResults.Count == 1)
|
||||
{
|
||||
return RerunResults[0].Passed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RerunResults.Where(r => r.Passed).Count() >= requiredNumberOfPasses;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Azure DevOps doesn't currently provide a way to directly report sub-results for tests that failed at least once
|
||||
// that were run multiple times. To get around that limitation, we'll mark the test as "Skip" since
|
||||
// that's the only non-pass/fail result we can return, and will then report the information about the
|
||||
// runs in the "reason" category for the skipped test. In order to save space, we'll make the following
|
||||
// optimizations for size:
|
||||
//
|
||||
// 1. Serialize as JSON, which is more compact than XML;
|
||||
// 2. Don't serialize values that we don't need;
|
||||
// 3. Store the URL prefix and suffix for the blob storage URL only once instead of
|
||||
// storing every log and screenshot URL in its entirety; and
|
||||
// 4. Store a list of unique error messages and then index into that instead of
|
||||
// storing every error message in its entirety.
|
||||
//
|
||||
// #4 is motivated by the fact that if a test fails multiple times, it probably failed for the same reason
|
||||
// each time, in which case we'd just be repeating ourselves if we stored every error message each time.
|
||||
//
|
||||
// TODO (https://github.com/dotnet/arcade/issues/2773): Once we're able to directly report things in a
|
||||
// more granular fashion than just a binary pass/fail result, we should do that.
|
||||
//
|
||||
[DataContract]
|
||||
internal class JsonSerializableTestResults
|
||||
{
|
||||
[DataMember]
|
||||
internal string blobPrefix;
|
||||
|
||||
[DataMember]
|
||||
internal string blobSuffix;
|
||||
|
||||
[DataMember]
|
||||
internal string[] errors;
|
||||
|
||||
[DataMember]
|
||||
internal JsonSerializableTestResult[] results;
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
internal class JsonSerializableTestResult
|
||||
{
|
||||
[DataMember]
|
||||
internal string outcome;
|
||||
|
||||
[DataMember]
|
||||
internal int duration;
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal string log;
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal string[] screenshots;
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal int errorIndex;
|
||||
}
|
||||
|
||||
public class TestPass
|
||||
{
|
||||
public TimeSpan TestPassExecutionTime { get; set; }
|
||||
public List<TestResult> TestResults { get; set; }
|
||||
|
||||
public static TestPass ParseTestWttFile(string fileName, bool cleanupFailuresAreRegressions, bool truncateTestNames)
|
||||
{
|
||||
using (var stream = File.OpenRead(fileName))
|
||||
{
|
||||
var doc = XDocument.Load(stream);
|
||||
var testResults = new List<TestResult>();
|
||||
var testExecutionTimeMap = new Dictionary<string, List<double>>();
|
||||
|
||||
TestResult currentResult = null;
|
||||
long frequency = 0;
|
||||
long startTime = 0;
|
||||
long stopTime = 0;
|
||||
bool inTestCleanup = false;
|
||||
|
||||
bool shouldLogToTestDetails = false;
|
||||
|
||||
long testPassStartTime = 0;
|
||||
long testPassStopTime = 0;
|
||||
|
||||
Func<XElement, bool> isScopeData = (elt) =>
|
||||
{
|
||||
return
|
||||
elt.Element("Data") != null &&
|
||||
elt.Element("Data").Element("WexContext") != null &&
|
||||
(
|
||||
elt.Element("Data").Element("WexContext").Value == "Cleanup" ||
|
||||
elt.Element("Data").Element("WexContext").Value == "TestScope" ||
|
||||
elt.Element("Data").Element("WexContext").Value == "TestScope" ||
|
||||
elt.Element("Data").Element("WexContext").Value == "ClassScope" ||
|
||||
elt.Element("Data").Element("WexContext").Value == "ModuleScope"
|
||||
);
|
||||
};
|
||||
|
||||
Func<XElement, bool> isModuleOrClassScopeStart = (elt) =>
|
||||
{
|
||||
return
|
||||
elt.Name == "Msg" &&
|
||||
elt.Element("Data") != null &&
|
||||
elt.Element("Data").Element("StartGroup") != null &&
|
||||
elt.Element("Data").Element("WexContext") != null &&
|
||||
(elt.Element("Data").Element("WexContext").Value == "ClassScope" ||
|
||||
elt.Element("Data").Element("WexContext").Value == "ModuleScope");
|
||||
};
|
||||
|
||||
Func<XElement, bool> isModuleScopeEnd = (elt) =>
|
||||
{
|
||||
return
|
||||
elt.Name == "Msg" &&
|
||||
elt.Element("Data") != null &&
|
||||
elt.Element("Data").Element("EndGroup") != null &&
|
||||
elt.Element("Data").Element("WexContext") != null &&
|
||||
elt.Element("Data").Element("WexContext").Value == "ModuleScope";
|
||||
};
|
||||
|
||||
Func<XElement, bool> isClassScopeEnd = (elt) =>
|
||||
{
|
||||
return
|
||||
elt.Name == "Msg" &&
|
||||
elt.Element("Data") != null &&
|
||||
elt.Element("Data").Element("EndGroup") != null &&
|
||||
elt.Element("Data").Element("WexContext") != null &&
|
||||
elt.Element("Data").Element("WexContext").Value == "ClassScope";
|
||||
};
|
||||
|
||||
int testsExecuting = 0;
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
// Capturing the frequency data to record accurate
|
||||
// timing data.
|
||||
if (element.Name == "RTI")
|
||||
{
|
||||
frequency = Int64.Parse(element.Attribute("Frequency").Value);
|
||||
}
|
||||
|
||||
// It's possible for a test to launch another test. If that happens, we won't modify the
|
||||
// current result. Instead, we'll continue operating like normal and expect that we get two
|
||||
// EndTests nodes before our next StartTests. We'll check that we've actually got a stop time
|
||||
// before creating a new result. This will result in the two results being squashed
|
||||
// into one result of the outer test that ran the inner one.
|
||||
if (element.Name == "StartTest")
|
||||
{
|
||||
testsExecuting++;
|
||||
if (testsExecuting == 1)
|
||||
{
|
||||
string testName = element.Attribute("Title").Value;
|
||||
|
||||
if (truncateTestNames)
|
||||
{
|
||||
const string xamlNativePrefix = "Windows::UI::Xaml::Tests::";
|
||||
const string xamlManagedPrefix = "Windows.UI.Xaml.Tests.";
|
||||
if (testName.StartsWith(xamlNativePrefix))
|
||||
{
|
||||
testName = testName.Substring(xamlNativePrefix.Length);
|
||||
}
|
||||
else if (testName.StartsWith(xamlManagedPrefix))
|
||||
{
|
||||
testName = testName.Substring(xamlManagedPrefix.Length);
|
||||
}
|
||||
}
|
||||
|
||||
currentResult = new TestResult() { Name = testName, SourceWttFile = fileName, Passed = true, CleanupPassed = true };
|
||||
testResults.Add(currentResult);
|
||||
startTime = Int64.Parse(element.Descendants("WexTraceInfo").First().Attribute("TimeStamp").Value);
|
||||
inTestCleanup = false;
|
||||
shouldLogToTestDetails = true;
|
||||
stopTime = 0;
|
||||
}
|
||||
}
|
||||
else if (currentResult != null && element.Name == "EndTest")
|
||||
{
|
||||
testsExecuting--;
|
||||
|
||||
// If any inner test fails, we'll still fail the outer
|
||||
currentResult.Passed &= element.Attribute("Result").Value == "Pass";
|
||||
|
||||
// Only gather execution data if this is the outer test we ran initially
|
||||
if (testsExecuting == 0)
|
||||
{
|
||||
stopTime = Int64.Parse(element.Descendants("WexTraceInfo").First().Attribute("TimeStamp").Value);
|
||||
if (!testExecutionTimeMap.Keys.Contains(currentResult.Name))
|
||||
testExecutionTimeMap[currentResult.Name] = new List<double>();
|
||||
testExecutionTimeMap[currentResult.Name].Add((double)(stopTime - startTime) / frequency);
|
||||
currentResult.ExecutionTime = TimeSpan.FromSeconds(testExecutionTimeMap[currentResult.Name].Average());
|
||||
|
||||
startTime = 0;
|
||||
inTestCleanup = true;
|
||||
}
|
||||
}
|
||||
else if (currentResult != null &&
|
||||
(isModuleOrClassScopeStart(element) || isModuleScopeEnd(element) || isClassScopeEnd(element)))
|
||||
{
|
||||
shouldLogToTestDetails = false;
|
||||
inTestCleanup = false;
|
||||
}
|
||||
|
||||
// Log-appending methods.
|
||||
if (currentResult != null && element.Name == "Error")
|
||||
{
|
||||
if (shouldLogToTestDetails)
|
||||
{
|
||||
currentResult.Details += "\r\n[Error]: " + element.Attribute("UserText").Value;
|
||||
if (element.Attribute("File") != null && element.Attribute("File").Value != "")
|
||||
{
|
||||
currentResult.Details += (" [File " + element.Attribute("File").Value);
|
||||
if (element.Attribute("Line") != null)
|
||||
currentResult.Details += " Line: " + element.Attribute("Line").Value;
|
||||
currentResult.Details += "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The test cleanup errors will often come after the test claimed to have
|
||||
// 'passed'. We treat them as errors as well.
|
||||
if (inTestCleanup)
|
||||
{
|
||||
currentResult.CleanupPassed = false;
|
||||
currentResult.Passed = false;
|
||||
// In stress mode runs, this test will run n times before cleanup is run. If the cleanup
|
||||
// fails, we want to fail every test.
|
||||
if (cleanupFailuresAreRegressions)
|
||||
{
|
||||
foreach (var result in testResults.Where(res => res.Name == currentResult.Name))
|
||||
{
|
||||
result.Passed = false;
|
||||
result.CleanupPassed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentResult != null && element.Name == "Warn")
|
||||
{
|
||||
if (shouldLogToTestDetails)
|
||||
{
|
||||
currentResult.Details += "\r\n[Warn]: " + element.Attribute("UserText").Value;
|
||||
}
|
||||
|
||||
if (element.Attribute("File") != null && element.Attribute("File").Value != "")
|
||||
{
|
||||
currentResult.Details += (" [File " + element.Attribute("File").Value);
|
||||
if (element.Attribute("Line") != null)
|
||||
currentResult.Details += " Line: " + element.Attribute("Line").Value;
|
||||
currentResult.Details += "]";
|
||||
}
|
||||
}
|
||||
|
||||
if (currentResult != null && element.Name == "Msg")
|
||||
{
|
||||
var dataElement = element.Element("Data");
|
||||
if (dataElement != null)
|
||||
{
|
||||
var supportingInfo = dataElement.Element("SupportingInfo");
|
||||
if (supportingInfo != null)
|
||||
{
|
||||
var screenshots = supportingInfo.Elements("Item")
|
||||
.Where(item => GetAttributeValue(item, "Name") == "Screenshot")
|
||||
.Select(item => GetAttributeValue(item, "Value"));
|
||||
|
||||
foreach(var screenshot in screenshots)
|
||||
{
|
||||
string fileNameSuffix = string.Empty;
|
||||
|
||||
if (fileName.Contains("_rerun_multiple"))
|
||||
{
|
||||
fileNameSuffix = "_rerun_multiple";
|
||||
}
|
||||
else if (fileName.Contains("_rerun"))
|
||||
{
|
||||
fileNameSuffix = "_rerun";
|
||||
}
|
||||
|
||||
currentResult.Screenshots.Add(screenshot.Replace(".jpg", fileNameSuffix + ".jpg"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testPassStartTime = Int64.Parse(doc.Root.Descendants("WexTraceInfo").First().Attribute("TimeStamp").Value);
|
||||
testPassStopTime = Int64.Parse(doc.Root.Descendants("WexTraceInfo").Last().Attribute("TimeStamp").Value);
|
||||
|
||||
var testPassTime = TimeSpan.FromSeconds((double)(testPassStopTime - testPassStartTime) / frequency);
|
||||
|
||||
foreach (TestResult testResult in testResults)
|
||||
{
|
||||
if (testResult.Details != null)
|
||||
{
|
||||
testResult.Details = testResult.Details.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
var testpass = new TestPass
|
||||
{
|
||||
TestPassExecutionTime = testPassTime,
|
||||
TestResults = testResults
|
||||
};
|
||||
|
||||
return testpass;
|
||||
}
|
||||
}
|
||||
|
||||
public static TestPass ParseTestWttFileWithReruns(string fileName, string singleRerunFileName, string multipleRerunFileName, bool cleanupFailuresAreRegressions, bool truncateTestNames)
|
||||
{
|
||||
TestPass testPass = ParseTestWttFile(fileName, cleanupFailuresAreRegressions, truncateTestNames);
|
||||
TestPass singleRerunTestPass = File.Exists(singleRerunFileName) ? ParseTestWttFile(singleRerunFileName, cleanupFailuresAreRegressions, truncateTestNames) : null;
|
||||
TestPass multipleRerunTestPass = File.Exists(multipleRerunFileName) ? ParseTestWttFile(multipleRerunFileName, cleanupFailuresAreRegressions, truncateTestNames) : null;
|
||||
|
||||
List<TestResult> rerunTestResults = new List<TestResult>();
|
||||
|
||||
if (singleRerunTestPass != null)
|
||||
{
|
||||
rerunTestResults.AddRange(singleRerunTestPass.TestResults);
|
||||
}
|
||||
|
||||
if (multipleRerunTestPass != null)
|
||||
{
|
||||
rerunTestResults.AddRange(multipleRerunTestPass.TestResults);
|
||||
}
|
||||
|
||||
// For each failed test result, we'll check to see whether the test passed at least once upon rerun.
|
||||
// If so, we'll set PassedOnRerun to true to flag the fact that this is an unreliable test
|
||||
// rather than a genuine test failure.
|
||||
foreach (TestResult failedTestResult in testPass.TestResults.Where(r => !r.Passed))
|
||||
{
|
||||
failedTestResult.RerunResults.AddRange(rerunTestResults.Where(r => r.Name == failedTestResult.Name));
|
||||
}
|
||||
|
||||
return testPass;
|
||||
}
|
||||
|
||||
private static string GetAttributeValue(XElement element, string attributeName)
|
||||
{
|
||||
if(element.Attribute(attributeName) != null)
|
||||
{
|
||||
return element.Attribute(attributeName).Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FailedTestDetector
|
||||
{
|
||||
public static void OutputFailedTestQuery(string wttInputPath)
|
||||
{
|
||||
var testPass = TestPass.ParseTestWttFile(wttInputPath, cleanupFailuresAreRegressions: true, truncateTestNames: false);
|
||||
|
||||
List<string> failedTestNames = new List<string>();
|
||||
|
||||
foreach (var result in testPass.TestResults)
|
||||
{
|
||||
if (!result.Passed)
|
||||
{
|
||||
failedTestNames.Add(result.Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (failedTestNames.Count > 0)
|
||||
{
|
||||
string failedTestSelectQuery = "(@Name='";
|
||||
|
||||
for (int i = 0; i < failedTestNames.Count; i++)
|
||||
{
|
||||
failedTestSelectQuery += failedTestNames[i];
|
||||
|
||||
if (i < failedTestNames.Count - 1)
|
||||
{
|
||||
failedTestSelectQuery += "' or @Name='";
|
||||
}
|
||||
}
|
||||
|
||||
failedTestSelectQuery += "')";
|
||||
|
||||
Console.WriteLine(failedTestSelectQuery);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestResultParser
|
||||
{
|
||||
private string testNamePrefix;
|
||||
private string helixResultsContainerUri;
|
||||
private string helixResultsContainerRsas;
|
||||
|
||||
public TestResultParser(string testNamePrefix, string helixResultsContainerUri, string helixResultsContainerRsas)
|
||||
{
|
||||
this.testNamePrefix = testNamePrefix;
|
||||
this.helixResultsContainerUri = helixResultsContainerUri;
|
||||
this.helixResultsContainerRsas = helixResultsContainerRsas;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetSubResultsJsonByMethodName(string wttInputPath, string wttSingleRerunInputPath, string wttMultipleRerunInputPath)
|
||||
{
|
||||
Dictionary<string, string> subResultsJsonByMethod = new Dictionary<string, string>();
|
||||
TestPass testPass = TestPass.ParseTestWttFileWithReruns(wttInputPath, wttSingleRerunInputPath, wttMultipleRerunInputPath, cleanupFailuresAreRegressions: true, truncateTestNames: false);
|
||||
|
||||
foreach (var result in testPass.TestResults)
|
||||
{
|
||||
var methodName = result.Name.Substring(result.Name.LastIndexOf('.') + 1);
|
||||
|
||||
if (!result.Passed)
|
||||
{
|
||||
// If a test failed, we'll have rerun it multiple times. We'll record the results of each run
|
||||
// formatted as JSON.
|
||||
JsonSerializableTestResults serializableResults = new JsonSerializableTestResults();
|
||||
serializableResults.blobPrefix = helixResultsContainerUri;
|
||||
serializableResults.blobSuffix = helixResultsContainerRsas;
|
||||
|
||||
List<string> errorList = new List<string>();
|
||||
errorList.Add(result.Details);
|
||||
|
||||
foreach (TestResult rerunResult in result.RerunResults)
|
||||
{
|
||||
errorList.Add(rerunResult.Details);
|
||||
}
|
||||
|
||||
serializableResults.errors = errorList.Distinct().Where(s => s != null).ToArray();
|
||||
|
||||
var reason = new XElement("reason");
|
||||
List<JsonSerializableTestResult> serializableResultList = new List<JsonSerializableTestResult>();
|
||||
serializableResultList.Add(ConvertToSerializableResult(result, serializableResults.errors));
|
||||
|
||||
foreach (TestResult rerunResult in result.RerunResults)
|
||||
{
|
||||
serializableResultList.Add(ConvertToSerializableResult(rerunResult, serializableResults.errors));
|
||||
}
|
||||
|
||||
serializableResults.results = serializableResultList.ToArray();
|
||||
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(JsonSerializableTestResults));
|
||||
serializer.WriteObject(stream, serializableResults);
|
||||
stream.Position = 0;
|
||||
|
||||
using (StreamReader streamReader = new StreamReader(stream))
|
||||
{
|
||||
subResultsJsonByMethod.Add(methodName, streamReader.ReadToEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return subResultsJsonByMethod;
|
||||
}
|
||||
|
||||
public void ConvertWttLogToXUnitLog(string wttInputPath, string wttSingleRerunInputPath, string wttMultipleRerunInputPath, string xunitOutputPath, int requiredPassRateThreshold)
|
||||
{
|
||||
TestPass testPass = TestPass.ParseTestWttFileWithReruns(wttInputPath, wttSingleRerunInputPath, wttMultipleRerunInputPath, cleanupFailuresAreRegressions: true, truncateTestNames: false);
|
||||
var results = testPass.TestResults;
|
||||
|
||||
int resultCount = results.Count;
|
||||
int passedCount = results.Where(r => r.Passed).Count();
|
||||
|
||||
// Since we re-run tests on failure, we'll mark every test that failed at least once as "skipped" rather than "failed".
|
||||
// If the test failed sufficiently often enough for it to count as a failed test (determined by a property on the
|
||||
// Azure DevOps job), we'll later mark it as failed during test results processing.
|
||||
|
||||
int failedCount = results.Where(r => !r.PassedOrUnreliable(requiredPassRateThreshold)).Count();
|
||||
int skippedCount = results.Where(r => !r.Passed && r.PassedOrUnreliable(requiredPassRateThreshold)).Count();
|
||||
|
||||
var root = new XElement("assemblies");
|
||||
|
||||
var assembly = new XElement("assembly");
|
||||
assembly.SetAttributeValue("name", "MUXControls.Test.dll");
|
||||
assembly.SetAttributeValue("test-framework", "TAEF");
|
||||
assembly.SetAttributeValue("run-date", DateTime.Now.ToString("yyyy-MM-dd"));
|
||||
|
||||
// This doesn't need to be completely accurate since it's not exposed anywhere.
|
||||
// If we need accurate an start time we can probably calculate it from the te.wtl file, but for
|
||||
// now this is fine.
|
||||
assembly.SetAttributeValue("run-time", (DateTime.Now - testPass.TestPassExecutionTime).ToString("hh:mm:ss"));
|
||||
|
||||
assembly.SetAttributeValue("total", resultCount);
|
||||
assembly.SetAttributeValue("passed", passedCount);
|
||||
assembly.SetAttributeValue("failed", failedCount);
|
||||
assembly.SetAttributeValue("skipped", skippedCount);
|
||||
|
||||
assembly.SetAttributeValue("time", (int)testPass.TestPassExecutionTime.TotalSeconds);
|
||||
assembly.SetAttributeValue("errors", 0);
|
||||
root.Add(assembly);
|
||||
|
||||
var collection = new XElement("collection");
|
||||
collection.SetAttributeValue("total", resultCount);
|
||||
collection.SetAttributeValue("passed", passedCount);
|
||||
collection.SetAttributeValue("failed", failedCount);
|
||||
collection.SetAttributeValue("skipped", skippedCount);
|
||||
collection.SetAttributeValue("name", "Test collection");
|
||||
collection.SetAttributeValue("time", (int)testPass.TestPassExecutionTime.TotalSeconds);
|
||||
assembly.Add(collection);
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
var test = new XElement("test");
|
||||
test.SetAttributeValue("name", testNamePrefix + "." + result.Name);
|
||||
|
||||
var className = GetTestClassName(result.Name);
|
||||
var methodName = GetTestMethodName(result.Name);
|
||||
test.SetAttributeValue("type", className);
|
||||
test.SetAttributeValue("method", methodName);
|
||||
|
||||
test.SetAttributeValue("time", result.ExecutionTime.TotalSeconds);
|
||||
|
||||
string resultString = string.Empty;
|
||||
|
||||
if (result.Passed)
|
||||
{
|
||||
resultString = "Pass";
|
||||
}
|
||||
else if(result.PassedOrUnreliable(requiredPassRateThreshold))
|
||||
{
|
||||
resultString = "Skip";
|
||||
}
|
||||
else
|
||||
{
|
||||
resultString = "Fail";
|
||||
}
|
||||
|
||||
|
||||
test.SetAttributeValue("result", resultString);
|
||||
|
||||
if (!result.Passed)
|
||||
{
|
||||
// If a test failed, we'll have rerun it multiple times.
|
||||
// We'll save the subresults to a JSON text file that we'll upload to the helix results container -
|
||||
// this allows it to be as long as we want, whereas the reason field in Azure DevOps has a 4000 character limit.
|
||||
string subResultsFileName = methodName + "_subresults.json";
|
||||
string subResultsFilePath = Path.Combine(Path.GetDirectoryName(wttInputPath), subResultsFileName);
|
||||
|
||||
if (result.PassedOrUnreliable(requiredPassRateThreshold))
|
||||
{
|
||||
var reason = new XElement("reason");
|
||||
reason.Add(new XCData(GetUploadedFileUrl(subResultsFileName, helixResultsContainerUri, helixResultsContainerRsas)));
|
||||
test.Add(reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
var failure = new XElement("failure");
|
||||
var message = new XElement("message");
|
||||
message.Add(new XCData(GetUploadedFileUrl(subResultsFileName, helixResultsContainerUri, helixResultsContainerRsas)));
|
||||
failure.Add(message);
|
||||
test.Add(failure);
|
||||
}
|
||||
}
|
||||
collection.Add(test);
|
||||
}
|
||||
|
||||
File.WriteAllText(xunitOutputPath, root.ToString());
|
||||
}
|
||||
|
||||
private JsonSerializableTestResult ConvertToSerializableResult(TestResult rerunResult, string[] uniqueErrors)
|
||||
{
|
||||
var serializableResult = new JsonSerializableTestResult();
|
||||
|
||||
serializableResult.outcome = rerunResult.Passed ? "Passed" : "Failed";
|
||||
serializableResult.duration = (int)Math.Round(rerunResult.ExecutionTime.TotalMilliseconds);
|
||||
|
||||
if (!rerunResult.Passed)
|
||||
{
|
||||
serializableResult.log = Path.GetFileName(rerunResult.SourceWttFile);
|
||||
|
||||
if (rerunResult.Screenshots.Any())
|
||||
{
|
||||
List<string> screenshots = new List<string>();
|
||||
|
||||
foreach (var screenshot in rerunResult.Screenshots)
|
||||
{
|
||||
screenshots.Add(Path.GetFileName(screenshot));
|
||||
}
|
||||
|
||||
serializableResult.screenshots = screenshots.ToArray();
|
||||
}
|
||||
|
||||
// To conserve space, we'll log the index of the error to index in a list of unique errors rather than
|
||||
// jotting down every single error in its entirety. We'll add one to the result so we can avoid
|
||||
// serializing this property when it has the default value of 0.
|
||||
serializableResult.errorIndex = Array.IndexOf(uniqueErrors, rerunResult.Details) + 1;
|
||||
}
|
||||
|
||||
return serializableResult;
|
||||
}
|
||||
|
||||
private string GetUploadedFileUrl(string filePath, string helixResultsContainerUri, string helixResultsContainerRsas)
|
||||
{
|
||||
var filename = Path.GetFileName(filePath);
|
||||
return string.Format("{0}/{1}{2}", helixResultsContainerUri, filename, helixResultsContainerRsas);
|
||||
}
|
||||
|
||||
private string GetTestNameSeparator(string testname)
|
||||
{
|
||||
var separatorString = ".";
|
||||
if (!testname.Contains(separatorString))
|
||||
{
|
||||
separatorString = "::";
|
||||
}
|
||||
return separatorString;
|
||||
}
|
||||
|
||||
private string GetTestMethodName(string fullyQualifiedName)
|
||||
{
|
||||
var separatorString = GetTestNameSeparator(fullyQualifiedName);
|
||||
var methodName = fullyQualifiedName.Substring(fullyQualifiedName.LastIndexOf(separatorString) + separatorString.Length);
|
||||
|
||||
return methodName;
|
||||
}
|
||||
|
||||
private string GetTestClassName(string fullyQualifiedName)
|
||||
{
|
||||
var separatorString = GetTestNameSeparator(fullyQualifiedName);
|
||||
var className = fullyQualifiedName.Substring(0, fullyQualifiedName.LastIndexOf(separatorString));
|
||||
|
||||
return className;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
build/Helix/InstallTestAppDependencies.ps1
Normal file
@@ -0,0 +1,12 @@
|
||||
# Displaying progress is unnecessary and is just distracting.
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
$dependencyFiles = Get-ChildItem -Filter "*Microsoft.VCLibs.*.appx"
|
||||
|
||||
foreach ($file in $dependencyFiles)
|
||||
{
|
||||
Write-Host "Adding dependency $($file)..."
|
||||
|
||||
Add-AppxPackage $file
|
||||
|
||||
}
|
||||
8
build/Helix/OutputFailedTestQuery.ps1
Normal file
@@ -0,0 +1,8 @@
|
||||
Param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttInputPath
|
||||
)
|
||||
|
||||
Add-Type -Language CSharp -ReferencedAssemblies System.Xml,System.Xml.Linq,System.Runtime.Serialization,System.Runtime.Serialization.Json (Get-Content $PSScriptRoot\HelixTestHelpers.cs -Raw)
|
||||
|
||||
[HelixTestHelpers.FailedTestDetector]::OutputFailedTestQuery($WttInputPath)
|
||||
32
build/Helix/OutputSubResultsJsonFiles.ps1
Normal file
@@ -0,0 +1,32 @@
|
||||
Param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttInputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttSingleRerunInputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WttMultipleRerunInputPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$TestNamePrefix
|
||||
)
|
||||
|
||||
# Ideally these would be passed as parameters to the script. However ps makes it difficult to deal with string literals containing '&', so we just
|
||||
# read the values directly from the environment variables
|
||||
$helixResultsContainerUri = $Env:HELIX_RESULTS_CONTAINER_URI
|
||||
$helixResultsContainerRsas = $Env:HELIX_RESULTS_CONTAINER_RSAS
|
||||
|
||||
Add-Type -Language CSharp -ReferencedAssemblies System.Xml,System.Xml.Linq,System.Runtime.Serialization,System.Runtime.Serialization.Json (Get-Content $PSScriptRoot\HelixTestHelpers.cs -Raw)
|
||||
|
||||
$testResultParser = [HelixTestHelpers.TestResultParser]::new($TestNamePrefix, $helixResultsContainerUri, $helixResultsContainerRsas)
|
||||
[System.Collections.Generic.Dictionary[string, string]]$subResultsJsonByMethodName = $testResultParser.GetSubResultsJsonByMethodName($WttInputPath, $WttSingleRerunInputPath, $WttMultipleRerunInputPath)
|
||||
|
||||
$subResultsJsonDirectory = [System.IO.Path]::GetDirectoryName($WttInputPath)
|
||||
|
||||
foreach ($methodName in $subResultsJsonByMethodName.Keys)
|
||||
{
|
||||
$subResultsJson = $subResultsJsonByMethodName[$methodName]
|
||||
$subResultsJsonPath = [System.IO.Path]::Combine($subResultsJsonDirectory, $methodName + "_subresults.json")
|
||||
Out-File $subResultsJsonPath -Encoding utf8 -InputObject $subResultsJson
|
||||
}
|
||||
131
build/Helix/OutputTestResults.ps1
Normal file
@@ -0,0 +1,131 @@
|
||||
Param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$MinimumExpectedTestsExecutedCount,
|
||||
|
||||
[string]$AccessToken = $env:SYSTEM_ACCESSTOKEN,
|
||||
[string]$CollectionUri = $env:SYSTEM_COLLECTIONURI,
|
||||
[string]$TeamProject = $env:SYSTEM_TEAMPROJECT,
|
||||
[string]$BuildUri = $env:BUILD_BUILDURI,
|
||||
[bool]$CheckJobAttempt
|
||||
)
|
||||
|
||||
$azureDevOpsRestApiHeaders = @{
|
||||
"Accept"="application/json"
|
||||
"Authorization"="Basic $([System.Convert]::ToBase64String([System.Text.ASCIIEncoding]::ASCII.GetBytes(":$AccessToken")))"
|
||||
}
|
||||
|
||||
. "$PSScriptRoot/AzurePipelinesHelperScripts.ps1"
|
||||
|
||||
Write-Host "Checking test results..."
|
||||
|
||||
$queryUri = GetQueryTestRunsUri -CollectionUri $CollectionUri -TeamProject $TeamProject -BuildUri $BuildUri -IncludeRunDetails
|
||||
Write-Host "queryUri = $queryUri"
|
||||
|
||||
$testRuns = Invoke-RestMethod -Uri $queryUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
[System.Collections.Generic.List[string]]$failingTests = @()
|
||||
[System.Collections.Generic.List[string]]$unreliableTests = @()
|
||||
[System.Collections.Generic.List[string]]$unexpectedResultTest = @()
|
||||
|
||||
[System.Collections.Generic.List[string]]$namesOfProcessedTestRuns = @()
|
||||
$totalTestsExecutedCount = 0
|
||||
|
||||
# We assume that we only have one testRun with a given name that we care about
|
||||
# We only process the last testRun with a given name (based on completedDate)
|
||||
# The name of a testRun is set to the Helix queue that it was run on (e.g. windows.10.amd64.client19h1.xaml)
|
||||
# If we have multiple test runs on the same queue that we care about, we will need to re-visit this logic
|
||||
foreach ($testRun in ($testRuns.value | Sort-Object -Property "completedDate" -Descending))
|
||||
{
|
||||
if ($CheckJobAttempt)
|
||||
{
|
||||
if ($namesOfProcessedTestRuns -contains $testRun.name)
|
||||
{
|
||||
Write-Host "Skipping test run '$($testRun.name)', since we have already processed a test run of that name."
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Processing results from test run '$($testRun.name)'"
|
||||
$namesOfProcessedTestRuns.Add($testRun.name)
|
||||
|
||||
$totalTestsExecutedCount += $testRun.totalTests
|
||||
|
||||
$testRunResultsUri = "$($testRun.url)/results?api-version=5.0"
|
||||
$testResults = Invoke-RestMethod -Uri "$($testRun.url)/results?api-version=5.0" -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
|
||||
foreach ($testResult in $testResults.value)
|
||||
{
|
||||
$shortTestCaseTitle = $testResult.testCaseTitle -replace "[a-zA-Z0-9]+.[a-zA-Z0-9]+.Windows.UI.Xaml.Tests.MUXControls.",""
|
||||
|
||||
if ($testResult.outcome -eq "Failed")
|
||||
{
|
||||
if (-not $failingTests.Contains($shortTestCaseTitle))
|
||||
{
|
||||
$failingTests.Add($shortTestCaseTitle)
|
||||
}
|
||||
}
|
||||
elseif ($testResult.outcome -eq "Warning")
|
||||
{
|
||||
if (-not $unreliableTests.Contains($shortTestCaseTitle))
|
||||
{
|
||||
$unreliableTests.Add($shortTestCaseTitle)
|
||||
}
|
||||
}
|
||||
elseif ($testResult.outcome -ne "Passed")
|
||||
{
|
||||
# We should only see tests with result "Passed", "Failed" or "Warning"
|
||||
if (-not $unexpectedResultTest.Contains($shortTestCaseTitle))
|
||||
{
|
||||
$unexpectedResultTest.Add($shortTestCaseTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($unreliableTests.Count -gt 0)
|
||||
{
|
||||
Write-Host @"
|
||||
##vso[task.logissue type=warning;]Unreliable tests:
|
||||
##vso[task.logissue type=warning;]$($unreliableTests -join "$([Environment]::NewLine)##vso[task.logissue type=warning;]")
|
||||
|
||||
"@
|
||||
}
|
||||
|
||||
if ($failingTests.Count -gt 0)
|
||||
{
|
||||
Write-Host @"
|
||||
##vso[task.logissue type=error;]Failing tests:
|
||||
##vso[task.logissue type=error;]$($failingTests -join "$([Environment]::NewLine)##vso[task.logissue type=error;]")
|
||||
|
||||
"@
|
||||
}
|
||||
|
||||
if ($unexpectedResultTest.Count -gt 0)
|
||||
{
|
||||
Write-Host @"
|
||||
##vso[task.logissue type=error;]Tests with unexpected results:
|
||||
##vso[task.logissue type=error;]$($unexpectedResultTest -join "$([Environment]::NewLine)##vso[task.logissue type=error;]")
|
||||
|
||||
"@
|
||||
}
|
||||
|
||||
if($totalTestsExecutedCount -lt $MinimumExpectedTestsExecutedCount)
|
||||
{
|
||||
Write-Host "Expected at least $MinimumExpectedTestsExecutedCount tests to be executed."
|
||||
Write-Host "Actual executed test count is: $totalTestsExecutedCount"
|
||||
Write-Host "##vso[task.complete result=Failed;]"
|
||||
}
|
||||
elseif ($failingTests.Count -gt 0)
|
||||
{
|
||||
Write-Host "At least one test failed."
|
||||
Write-Host "##vso[task.complete result=Failed;]"
|
||||
}
|
||||
elseif ($unreliableTests.Count -gt 0)
|
||||
{
|
||||
Write-Host "All tests eventually passed, but some initially failed."
|
||||
Write-Host "##vso[task.complete result=Succeeded;]"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "All tests passed."
|
||||
Write-Host "##vso[task.complete result=Succeeded;]"
|
||||
}
|
||||
54
build/Helix/PrepareHelixPayload.ps1
Normal file
@@ -0,0 +1,54 @@
|
||||
[CmdLetBinding()]
|
||||
Param(
|
||||
[string]$Platform,
|
||||
[string]$Configuration,
|
||||
[string]$ArtifactName='drop'
|
||||
)
|
||||
|
||||
$payloadDir = "HelixPayload\$Configuration\$Platform"
|
||||
|
||||
$repoDirectory = Join-Path (Split-Path -Parent $script:MyInvocation.MyCommand.Path) "..\..\"
|
||||
$nugetPackagesDir = Join-Path (Split-Path -Parent $script:MyInvocation.MyCommand.Path) "packages"
|
||||
|
||||
# Create the payload directory. Remove it if it already exists.
|
||||
If(test-path $payloadDir)
|
||||
{
|
||||
Remove-Item $payloadDir -Recurse
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $payloadDir
|
||||
|
||||
# Copy files from nuget packages
|
||||
Copy-Item "$nugetPackagesDir\microsoft.windows.apps.test.1.0.181203002\lib\netcoreapp2.1\*.dll" $payloadDir
|
||||
Copy-Item "$nugetPackagesDir\taef.redist.wlk.10.57.200731005-develop\build\Binaries\$Platform\*" $payloadDir
|
||||
Copy-Item "$nugetPackagesDir\taef.redist.wlk.10.57.200731005-develop\build\Binaries\$Platform\CoreClr\*" $payloadDir
|
||||
New-Item -ItemType Directory -Force -Path "$payloadDir\.NETCoreApp2.1\"
|
||||
Copy-Item "$nugetPackagesDir\runtime.win-$Platform.microsoft.netcore.app.2.1.0\runtimes\win-$Platform\lib\netcoreapp2.1\*" "$payloadDir\.NETCoreApp2.1\"
|
||||
Copy-Item "$nugetPackagesDir\runtime.win-$Platform.microsoft.netcore.app.2.1.0\runtimes\win-$Platform\native\*" "$payloadDir\.NETCoreApp2.1\"
|
||||
|
||||
function Copy-If-Exists
|
||||
{
|
||||
Param($source, $destinationDir)
|
||||
|
||||
if (Test-Path $source)
|
||||
{
|
||||
Write-Host "Copy from '$source' to '$destinationDir'"
|
||||
Copy-Item -Force $source $destinationDir
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "'$source' does not exist."
|
||||
}
|
||||
}
|
||||
|
||||
# Copy files from the 'drop' artifact dir
|
||||
Copy-Item "$repoDirectory\Artifacts\$ArtifactName\$Configuration\$Platform\Test\*" $payloadDir -Recurse
|
||||
|
||||
# Copy files from the repo
|
||||
New-Item -ItemType Directory -Force -Path "$payloadDir"
|
||||
Copy-Item "build\helix\ConvertWttLogToXUnit.ps1" "$payloadDir"
|
||||
Copy-Item "build\helix\OutputFailedTestQuery.ps1" "$payloadDir"
|
||||
Copy-Item "build\helix\OutputSubResultsJsonFiles.ps1" "$payloadDir"
|
||||
Copy-Item "build\helix\HelixTestHelpers.cs" "$payloadDir"
|
||||
Copy-Item "build\helix\runtests.cmd" $payloadDir
|
||||
Copy-Item "build\helix\InstallTestAppDependencies.ps1" "$payloadDir"
|
||||
Copy-Item "build\Helix\EnsureMachineState.ps1" "$payloadDir"
|
||||
112
build/Helix/ProcessHelixFiles.ps1
Normal file
@@ -0,0 +1,112 @@
|
||||
Param(
|
||||
[string]$AccessToken = $env:SYSTEM_ACCESSTOKEN,
|
||||
[string]$HelixAccessToken = $env:HelixAccessToken,
|
||||
[string]$CollectionUri = $env:SYSTEM_COLLECTIONURI,
|
||||
[string]$TeamProject = $env:SYSTEM_TEAMPROJECT,
|
||||
[string]$BuildUri = $env:BUILD_BUILDURI,
|
||||
[string]$OutputFolder = "HelixOutput"
|
||||
)
|
||||
|
||||
$helixLinkFile = "$OutputFolder\LinksToHelixTestFiles.html"
|
||||
|
||||
$accessTokenParam = ""
|
||||
if($HelixAccessToken)
|
||||
{
|
||||
$accessTokenParam = "?access_token=$HelixAccessToken"
|
||||
}
|
||||
|
||||
function Generate-File-Links
|
||||
{
|
||||
Param ([Array[]]$files,[string]$sectionName)
|
||||
if($files.Count -gt 0)
|
||||
{
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<div class=$sectionName>"
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<h4>$sectionName</h4>"
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<ul>"
|
||||
foreach($file in $files)
|
||||
{
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<li><a href=$($file.Link)>$($file.Name)</a></li>"
|
||||
}
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "</ul>"
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "</div>"
|
||||
}
|
||||
}
|
||||
|
||||
#Create output directory
|
||||
New-Item $OutputFolder -ItemType Directory
|
||||
|
||||
$azureDevOpsRestApiHeaders = @{
|
||||
"Accept"="application/json"
|
||||
"Authorization"="Basic $([System.Convert]::ToBase64String([System.Text.ASCIIEncoding]::ASCII.GetBytes(":$AccessToken")))"
|
||||
}
|
||||
|
||||
. "$PSScriptRoot/AzurePipelinesHelperScripts.ps1"
|
||||
|
||||
$queryUri = GetQueryTestRunsUri -CollectionUri $CollectionUri -TeamProject $TeamProject -BuildUri $BuildUri -IncludeRunDetails
|
||||
Write-Host "queryUri = $queryUri"
|
||||
|
||||
$testRuns = Invoke-RestMethod -Uri $queryUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
[System.Collections.Generic.List[string]]$workItems = @()
|
||||
|
||||
foreach ($testRun in $testRuns.value)
|
||||
{
|
||||
$testResults = Invoke-RestMethod -Uri "$($testRun.url)/results?api-version=5.0" -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
$isTestRunNameShown = $false
|
||||
|
||||
foreach ($testResult in $testResults.value)
|
||||
{
|
||||
if ("comment" -in $testResult)
|
||||
{
|
||||
$info = ConvertFrom-Json $testResult.comment
|
||||
$helixJobId = $info.HelixJobId
|
||||
$helixWorkItemName = $info.HelixWorkItemName
|
||||
|
||||
$workItem = "$helixJobId-$helixWorkItemName"
|
||||
|
||||
if (-not $workItems.Contains($workItem))
|
||||
{
|
||||
$workItems.Add($workItem)
|
||||
$filesQueryUri = "https://helix.dot.net/api/2019-06-17/jobs/$helixJobId/workitems/$helixWorkItemName/files$accessTokenParam"
|
||||
$files = Invoke-RestMethod -Uri $filesQueryUri -Method Get
|
||||
|
||||
$screenShots = $files | where { $_.Name.EndsWith(".jpg") }
|
||||
$dumps = $files | where { $_.Name.EndsWith(".dmp") }
|
||||
$pgcFiles = $files | where { $_.Name.EndsWith(".pgc") }
|
||||
if ($screenShots.Count + $dumps.Count + $pgcFiles.Count -gt 0)
|
||||
{
|
||||
if(-Not $isTestRunNameShown)
|
||||
{
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<h2>$($testRun.name)</h2>"
|
||||
$isTestRunNameShown = $true
|
||||
}
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<h3>$helixWorkItemName</h3>"
|
||||
Generate-File-Links $screenShots "Screenshots"
|
||||
Generate-File-Links $dumps "CrashDumps"
|
||||
Generate-File-Links $pgcFiles "PGC files"
|
||||
$misc = $files | where { ($screenShots -NotContains $_) -And ($dumps -NotContains $_) -And ($visualTreeVerificationFiles -NotContains $_) -And ($pgcFiles -NotContains $_) }
|
||||
Generate-File-Links $misc "Misc"
|
||||
|
||||
foreach($pgcFile in $pgcFiles)
|
||||
{
|
||||
$flavorPath = $pgcFile.Name.Split('.')[0]
|
||||
$archPath = $pgcFile.Name.Split('.')[1]
|
||||
$fileName = $pgcFile.Name.Remove(0, $flavorPath.length + $archPath.length + 2)
|
||||
$fullPath = "$OutputFolder\PGO\$flavorPath\$archPath"
|
||||
$destination = "$fullPath\$fileName"
|
||||
|
||||
Write-Host "Copying $($pgcFile.Name) to $destination"
|
||||
|
||||
if (-Not (Test-Path $fullPath))
|
||||
{
|
||||
New-Item $fullPath -ItemType Directory
|
||||
}
|
||||
|
||||
$link = "$($pgcFile.Link)$accessTokenParam"
|
||||
$webClient.DownloadFile($link, $destination)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
build/Helix/RunTestsInHelix.proj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.DotNet.Helix.Sdk" DefaultTargets="Test">
|
||||
<PropertyGroup>
|
||||
<HelixSource>pr/terminal/$(BUILD_SOURCEBRANCH)/</HelixSource>
|
||||
<EnableXUnitReporter>true</EnableXUnitReporter>
|
||||
<EnableAzurePipelinesReporter>true</EnableAzurePipelinesReporter>
|
||||
<FailOnMissionControlTestFailure>true</FailOnMissionControlTestFailure>
|
||||
<HelixPreCommands>$(HelixPreCommands);set testnameprefix=$(Configuration).$(Platform);set testbuildplatform=$(Platform);set rerunPassesRequiredToAvoidFailure=$(rerunPassesRequiredToAvoidFailure)</HelixPreCommands>
|
||||
<OutputPath>..\..\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<HelixCorrelationPayload Include="..\..\HelixPayload\$(Configuration)\$(Platform)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- These .proj files are generated by the build machine prior to running tests via GenerateTestProjFile.ps1. -->
|
||||
<Import Project="$(ProjFilesPath)\RunTestsInHelix-TerminalAppLocalTests.proj" Condition=" '$(TestSuite)'=='DevTestSuite' " />
|
||||
<Import Project="$(ProjFilesPath)\RunTestsInHelix-HostTestsUIA.proj" Condition=" '$(TestSuite)'=='DevTestSuite' " />
|
||||
</Project>
|
||||
135
build/Helix/UpdateUnreliableTests.ps1
Normal file
@@ -0,0 +1,135 @@
|
||||
[CmdLetBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$RerunPassesRequiredToAvoidFailure,
|
||||
|
||||
[string]$AccessToken = $env:SYSTEM_ACCESSTOKEN,
|
||||
[string]$CollectionUri = $env:SYSTEM_COLLECTIONURI,
|
||||
[string]$TeamProject = $env:SYSTEM_TEAMPROJECT,
|
||||
[string]$BuildUri = $env:BUILD_BUILDURI
|
||||
)
|
||||
|
||||
. "$PSScriptRoot/AzurePipelinesHelperScripts.ps1"
|
||||
|
||||
|
||||
$azureDevOpsRestApiHeaders = @{
|
||||
"Accept"="application/json"
|
||||
"Authorization"="Basic $([System.Convert]::ToBase64String([System.Text.ASCIIEncoding]::ASCII.GetBytes(":$AccessToken")))"
|
||||
}
|
||||
|
||||
$queryUri = GetQueryTestRunsUri -CollectionUri $CollectionUri -TeamProject $TeamProject -BuildUri $BuildUri
|
||||
Write-Host "queryUri = $queryUri"
|
||||
|
||||
# To account for unreliable tests, we'll iterate through all of the tests associated with this build, check to see any tests that were unreliable
|
||||
# (denoted by being marked as "skipped"), and if so, we'll instead mark those tests with a warning and enumerate all of the attempted runs
|
||||
# with their pass/fail states as well as any relevant error messages for failed attempts.
|
||||
$testRuns = Invoke-RestMethod -Uri $queryUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
|
||||
$timesSeenByRunName = @{}
|
||||
|
||||
foreach ($testRun in $testRuns.value)
|
||||
{
|
||||
$testRunResultsUri = "$($testRun.url)/results?api-version=5.0"
|
||||
|
||||
Write-Host "Marking test run `"$($testRun.name)`" as in progress so we can change its results to account for unreliable tests."
|
||||
Invoke-RestMethod -Uri "$($testRun.url)?api-version=5.0" -Method Patch -Body (ConvertTo-Json @{ "state" = "InProgress" }) -Headers $azureDevOpsRestApiHeaders -ContentType "application/json" | Out-Null
|
||||
|
||||
Write-Host "Retrieving test results..."
|
||||
$testResults = Invoke-RestMethod -Uri $testRunResultsUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
|
||||
foreach ($testResult in $testResults.value)
|
||||
{
|
||||
$testNeedsSubResultProcessing = $false
|
||||
if ($testResult.outcome -eq "NotExecuted")
|
||||
{
|
||||
$testNeedsSubResultProcessing = $true
|
||||
}
|
||||
elseif($testResult.outcome -eq "Failed")
|
||||
{
|
||||
$testNeedsSubResultProcessing = $testResult.errorMessage -like "*_subresults.json*"
|
||||
}
|
||||
|
||||
if ($testNeedsSubResultProcessing)
|
||||
{
|
||||
Write-Host " Test $($testResult.testCaseTitle) was detected as unreliable. Updating..."
|
||||
|
||||
# The errorMessage field contains a link to the JSON-encoded rerun result data.
|
||||
$rerunResults = ConvertFrom-Json (New-Object System.Net.WebClient).DownloadString($testResult.errorMessage)
|
||||
[System.Collections.Generic.List[System.Collections.Hashtable]]$rerunDataList = @()
|
||||
$attemptCount = 0
|
||||
$passCount = 0
|
||||
$totalDuration = 0
|
||||
|
||||
foreach ($rerun in $rerunResults.results)
|
||||
{
|
||||
$rerunData = @{
|
||||
"displayName" = "Attempt #$($attemptCount + 1) - $($testResult.testCaseTitle)";
|
||||
"durationInMs" = $rerun.duration;
|
||||
"outcome" = $rerun.outcome;
|
||||
}
|
||||
|
||||
if ($rerun.outcome -eq "Passed")
|
||||
{
|
||||
$passCount++
|
||||
}
|
||||
|
||||
if ($attemptCount -gt 0)
|
||||
{
|
||||
$rerunData["sequenceId"] = $attemptCount
|
||||
}
|
||||
|
||||
Write-Host " Attempt #$($attemptCount + 1): $($rerun.outcome)"
|
||||
|
||||
if ($rerun.outcome -ne "Passed")
|
||||
{
|
||||
$screenshots = "$($rerunResults.blobPrefix)/$($rerun.screenshots -join @"
|
||||
$($rerunResults.blobSuffix)
|
||||
$($rerunResults.blobPrefix)
|
||||
"@)$($rerunResults.blobSuffix)"
|
||||
|
||||
# We subtract 1 from the error index because we added 1 so we could use 0
|
||||
# as a default value not injected into the JSON in order to keep its size down.
|
||||
# We did this because there's a maximum size enforced for the errorMessage parameter
|
||||
# in the Azure DevOps REST API.
|
||||
$fullErrorMessage = @"
|
||||
Log: $($rerunResults.blobPrefix)/$($rerun.log)$($rerunResults.blobSuffix)
|
||||
|
||||
Screenshots:
|
||||
$screenshots
|
||||
|
||||
Error log:
|
||||
$($rerunResults.errors[$rerun.errorIndex - 1])
|
||||
"@
|
||||
|
||||
$rerunData["errorMessage"] = $fullErrorMessage
|
||||
}
|
||||
|
||||
$attemptCount++
|
||||
$totalDuration += $rerun.duration
|
||||
$rerunDataList.Add($rerunData)
|
||||
}
|
||||
|
||||
$overallOutcome = "Warning"
|
||||
|
||||
if ($attemptCount -eq 2)
|
||||
{
|
||||
Write-Host " Test $($testResult.testCaseTitle) passed on the immediate rerun, so we'll mark it as unreliable."
|
||||
}
|
||||
elseif ($passCount -gt $RerunPassesRequiredToAvoidFailure)
|
||||
{
|
||||
Write-Host " Test $($testResult.testCaseTitle) passed on $passCount of $attemptCount attempts, which is greater than or equal to the $RerunPassesRequiredToAvoidFailure passes required to avoid being marked as failed. Marking as unreliable."
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host " Test $($testResult.testCaseTitle) passed on only $passCount of $attemptCount attempts, which is less than the $RerunPassesRequiredToAvoidFailure passes required to avoid being marked as failed. Marking as failed."
|
||||
$overallOutcome = "Failed"
|
||||
}
|
||||
|
||||
$updateBody = ConvertTo-Json @(@{ "id" = $testResult.id; "outcome" = $overallOutcome; "errorMessage" = " "; "durationInMs" = $totalDuration; "subResults" = $rerunDataList; "resultGroupType" = "rerun" }) -Depth 5
|
||||
Invoke-RestMethod -Uri $testRunResultsUri -Method Patch -Headers $azureDevOpsRestApiHeaders -Body $updateBody -ContentType "application/json" | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Finished updates. Re-marking test run `"$($testRun.name)`" as completed."
|
||||
Invoke-RestMethod -Uri "$($testRun.url)?api-version=5.0" -Method Patch -Body (ConvertTo-Json @{ "state" = "Completed" }) -Headers $azureDevOpsRestApiHeaders -ContentType "application/json" | Out-Null
|
||||
}
|
||||
5
build/Helix/global.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20277.5"
|
||||
}
|
||||
}
|
||||
8
build/Helix/packages.config
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="TAEF.Redist.Wlk" version="10.57.200731005-develop" targetFramework="native" />
|
||||
<package id="microsoft.windows.apps.test" version="1.0.181203002" targetFramework="native" />
|
||||
<package id="runtime.win-x86.microsoft.netcore.app" version="2.1.0" targetFramework="native" />
|
||||
<package id="runtime.win-x64.microsoft.netcore.app" version="2.1.0" targetFramework="native" />
|
||||
</packages>
|
||||
32
build/Helix/readme.md
Normal file
@@ -0,0 +1,32 @@
|
||||
This directory contains code and configuration files to run WinUI tests in Helix.
|
||||
|
||||
Helix is a cloud hosted test execution environment which is accessed via the Arcade SDK.
|
||||
More details:
|
||||
* [Arcade](https://github.com/dotnet/arcade)
|
||||
* [Helix](https://github.com/dotnet/arcade/tree/master/src/Microsoft.DotNet.Helix/Sdk)
|
||||
|
||||
WinUI tests are scheduled in Helix by the Azure DevOps Pipeline: [RunHelixTests.yml](../RunHelixTests.yml).
|
||||
|
||||
The workflow is as follows:
|
||||
1. NuGet Restore is called on the packages.config in this directory. This downloads any runtime dependencies
|
||||
that are needed to run tests.
|
||||
2. PrepareHelixPayload.ps1 is called. This copies the necessary files from various locations into a Helix
|
||||
payload directory. This directory is what will get sent to the Helix machines.
|
||||
3. RunTestsInHelix.proj is executed. This proj has a dependency on
|
||||
[Microsoft.DotNet.Helix.Sdk](https://github.com/dotnet/arcade/tree/master/src/Microsoft.DotNet.Helix/Sdk)
|
||||
which it uses to publish the Helix payload directory and to schedule the Helix Work Items. The WinUI tests
|
||||
are parallelized into multiple Helix Work Items.
|
||||
4. Each Helix Work Item calls [runtests.cmd](runtests.cmd) with a specific query to pass to
|
||||
[TAEF](https://docs.microsoft.com/en-us/windows-hardware/drivers/taef/) which runs the tests.
|
||||
5. If a test is detected to have failed, we run it again, first once, then eight more times if it fails again.
|
||||
If it fails all ten times, we report the test as failed; otherwise, we report it as unreliable,
|
||||
which will show up as a warning, but which will not fail the build. When a test is reported as unreliable,
|
||||
we include the results for each individual run via a JSON string in the original test's errorMessage field.
|
||||
6. TAEF produces logs in WTT format. Helix is able to process logs in XUnit format. We run
|
||||
[ConvertWttLogToXUnit.ps1](ConvertWttLogToXUnit.ps1) to convert the logs into the necessary format.
|
||||
7. RunTestsInHelix.proj has EnableAzurePipelinesReporter set to true. This allows the XUnit formatted test
|
||||
results to be reported back to the Azure DevOps Pipeline.
|
||||
8. We process unreliable tests once all tests have been reported by reading the JSON string from the
|
||||
errorMessage field and calling the Azure DevOps REST API to modify the unreliable tests to have sub-results
|
||||
added to the test and to mark the test as "warning", which will enable people to see exactly how the test
|
||||
failed in runs where it did.
|
||||
106
build/Helix/runtests.cmd
Normal file
@@ -0,0 +1,106 @@
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
|
||||
echo %TIME%
|
||||
|
||||
robocopy %HELIX_CORRELATION_PAYLOAD% . /s /NP > NUL
|
||||
|
||||
echo %TIME%
|
||||
|
||||
reg add HKLM\Software\Policies\Microsoft\Windows\Appx /v AllowAllTrustedApps /t REG_DWORD /d 1 /f
|
||||
|
||||
rem enable dump collection for our test apps:
|
||||
rem note, this script is run from a 32-bit cmd, but we need to set the native reg-key
|
||||
FOR %%A IN (TestHostApp.exe,te.exe,te.processhost.exe,conhost.exe,OpenConsole.exe,WindowsTerminal.exe) DO (
|
||||
%systemroot%\sysnative\cmd.exe /c reg add "HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\%%A" /v DumpFolder /t REG_EXPAND_SZ /d %HELIX_DUMP_FOLDER% /f
|
||||
%systemroot%\sysnative\cmd.exe /c reg add "HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\%%A" /v DumpType /t REG_DWORD /d 2 /f
|
||||
%systemroot%\sysnative\cmd.exe /c reg add "HKLM\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\%%A" /v DumpCount /t REG_DWORD /d 10 /f
|
||||
)
|
||||
|
||||
echo %TIME%
|
||||
|
||||
:: kill dhandler, which is a tool designed to handle unexpected windows appearing. But since our tests are
|
||||
:: expected to show UI we don't want it running.
|
||||
taskkill -f -im dhandler.exe
|
||||
|
||||
echo %TIME%
|
||||
powershell -ExecutionPolicy Bypass .\EnsureMachineState.ps1
|
||||
echo %TIME%
|
||||
powershell -ExecutionPolicy Bypass .\InstallTestAppDependencies.ps1
|
||||
echo %TIME%
|
||||
|
||||
set testBinaryCandidates=TerminalApp.LocalTests.dll Conhost.UIA.Tests.dll
|
||||
set testBinaries=
|
||||
for %%B in (%testBinaryCandidates%) do (
|
||||
if exist %%B (
|
||||
set "testBinaries=!testBinaries! %%B"
|
||||
)
|
||||
)
|
||||
|
||||
echo %TIME%
|
||||
te.exe %testBinaries% /enablewttlogging /unicodeOutput:false /sessionTimeout:0:15 /testtimeout:0:10 /screenCaptureOnError %*
|
||||
echo %TIME%
|
||||
|
||||
powershell -ExecutionPolicy Bypass Get-Process
|
||||
|
||||
move te.wtl te_original.wtl
|
||||
|
||||
copy /y te_original.wtl %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
copy /y WexLogFileOutput\*.jpg %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
for /f "tokens=* delims=" %%a in ('dir /b *.pgc') do ren "%%a" "%testnameprefix%.%%~na.pgc"
|
||||
copy /y *.pgc %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
|
||||
set FailedTestQuery=
|
||||
for /F "tokens=* usebackq" %%I IN (`powershell -ExecutionPolicy Bypass .\OutputFailedTestQuery.ps1 te_original.wtl`) DO (
|
||||
set FailedTestQuery=%%I
|
||||
)
|
||||
|
||||
rem The first time, we'll just re-run failed tests once. In many cases, tests fail very rarely, such that
|
||||
rem a single re-run will be sufficient to detect many unreliable tests.
|
||||
if "%FailedTestQuery%" == "" goto :SkipReruns
|
||||
|
||||
echo %TIME%
|
||||
te.exe %testBinaries% /enablewttlogging /unicodeOutput:false /sessionTimeout:0:15 /testtimeout:0:10 /screenCaptureOnError /select:"%FailedTestQuery%"
|
||||
echo %TIME%
|
||||
|
||||
move te.wtl te_rerun.wtl
|
||||
|
||||
copy /y te_rerun.wtl %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
copy /y WexLogFileOutput\*.jpg %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
|
||||
rem If there are still failing tests remaining, we'll run them eight more times, so they'll have been run a total of ten times.
|
||||
rem If any tests fail all ten times, we can be pretty confident that these are actual test failures rather than unreliable tests.
|
||||
if not exist te_rerun.wtl goto :SkipReruns
|
||||
|
||||
set FailedTestQuery=
|
||||
for /F "tokens=* usebackq" %%I IN (`powershell -ExecutionPolicy Bypass .\OutputFailedTestQuery.ps1 te_rerun.wtl`) DO (
|
||||
set FailedTestQuery=%%I
|
||||
)
|
||||
|
||||
if "%FailedTestQuery%" == "" goto :SkipReruns
|
||||
|
||||
echo %TIME%
|
||||
te.exe %testBinaries% /enablewttlogging /unicodeOutput:false /sessionTimeout:0:15 /testtimeout:0:10 /screenCaptureOnError /testmode:Loop /LoopTest:8 /select:"%FailedTestQuery%"
|
||||
echo %TIME%
|
||||
|
||||
powershell -ExecutionPolicy Bypass Get-Process
|
||||
|
||||
move te.wtl te_rerun_multiple.wtl
|
||||
|
||||
copy /y te_rerun_multiple.wtl %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
copy /y WexLogFileOutput\*.jpg %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
powershell -ExecutionPolicy Bypass .\CopyVisualTreeVerificationFiles.ps1
|
||||
|
||||
:SkipReruns
|
||||
|
||||
powershell -ExecutionPolicy Bypass Get-Process
|
||||
|
||||
echo %TIME%
|
||||
powershell -ExecutionPolicy Bypass .\OutputSubResultsJsonFiles.ps1 te_original.wtl te_rerun.wtl te_rerun_multiple.wtl %testnameprefix%
|
||||
powershell -ExecutionPolicy Bypass .\ConvertWttLogToXUnit.ps1 te_original.wtl te_rerun.wtl te_rerun_multiple.wtl testResults.xml %testnameprefix%
|
||||
echo %TIME%
|
||||
|
||||
copy /y *_subresults.json %HELIX_WORKITEM_UPLOAD_ROOT%
|
||||
|
||||
type testResults.xml
|
||||
|
||||
echo %TIME%
|
||||
5
build/packages.config
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="TAEF.Redist.Wlk" version="10.57.200731005-develop" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -2,7 +2,8 @@ trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- main
|
||||
- feature/*
|
||||
paths:
|
||||
exclude:
|
||||
- doc/*
|
||||
@@ -12,7 +13,8 @@ trigger:
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- main
|
||||
- feature/*
|
||||
paths:
|
||||
exclude:
|
||||
- doc/*
|
||||
|
||||
@@ -8,7 +8,9 @@ jobs:
|
||||
variables:
|
||||
BuildConfiguration: AuditMode
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
pool: { vmImage: windows-2019 }
|
||||
pool: "windevbuildagents"
|
||||
# The public pool is also an option!
|
||||
# pool: { vmImage: windows-2019 }
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
|
||||
@@ -2,6 +2,8 @@ parameters:
|
||||
configuration: 'Release'
|
||||
platform: ''
|
||||
additionalBuildArguments: ''
|
||||
minimumExpectedTestsExecutedCount: 10 # Sanity check for minimum expected tests to be reported
|
||||
rerunPassesRequiredToAvoidFailure: 5
|
||||
|
||||
jobs:
|
||||
- job: Build${{ parameters.platform }}${{ parameters.configuration }}
|
||||
@@ -9,9 +11,27 @@ jobs:
|
||||
variables:
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
pool: { vmImage: windows-2019 }
|
||||
pool: "windevbuildagents"
|
||||
# The public pool is also an option!
|
||||
# pool: { vmImage: windows-2019 }
|
||||
|
||||
steps:
|
||||
- template: build-console-steps.yml
|
||||
parameters:
|
||||
additionalBuildArguments: ${{ parameters.additionalBuildArguments }}
|
||||
|
||||
- template: helix-runtests-job.yml
|
||||
parameters:
|
||||
name: 'RunTestsInHelix'
|
||||
dependsOn: Build${{ parameters.platform }}${{ parameters.configuration }}
|
||||
condition: and(succeeded(), and(eq('${{ parameters.platform }}', 'x64'), not(eq(variables['Build.Reason'], 'PullRequest'))))
|
||||
testSuite: 'DevTestSuite'
|
||||
rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
|
||||
|
||||
- template: helix-processtestresults-job.yml
|
||||
parameters:
|
||||
dependsOn:
|
||||
- RunTestsInHelix
|
||||
condition: and(succeededOrFailed(), and(eq('${{ parameters.platform }}', 'x64'), not(eq(variables['Build.Reason'], 'PullRequest'))))
|
||||
rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
|
||||
minimumExpectedTestsExecutedCount: ${{ parameters.minimumExpectedTestsExecutedCount }}
|
||||
@@ -1,5 +1,6 @@
|
||||
parameters:
|
||||
additionalBuildArguments: ''
|
||||
testLogPath: '$(Build.BinariesDirectory)\$(BuildPlatform)\$(BuildConfiguration)\testsOnBuildMachine.wtl'
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
@@ -7,23 +8,29 @@ steps:
|
||||
clean: true
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: Ensure NuGet 4.8.1
|
||||
displayName: 'Use NuGet 5.2.0'
|
||||
inputs:
|
||||
versionSpec: 4.8.1
|
||||
|
||||
- task: VisualStudioTestPlatformInstaller@1
|
||||
displayName: Ensure VSTest Platform
|
||||
versionSpec: 5.2.0
|
||||
|
||||
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
|
||||
# This should be `task: NuGetCommand@2`
|
||||
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
|
||||
displayName: Restore NuGet packages
|
||||
displayName: Restore NuGet packages for solution
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: OpenConsole.sln
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\packages'
|
||||
|
||||
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
|
||||
displayName: Restore NuGet packages for extraneous build actions
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: NuGet.config
|
||||
restoreSolution: build/packages.config
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\packages'
|
||||
|
||||
- task: VSBuild@1
|
||||
displayName: 'Build solution **\OpenConsole.sln'
|
||||
@@ -66,7 +73,7 @@ steps:
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: -MatchPattern '*unit.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)'
|
||||
arguments: -MatchPattern '*unit.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)' -LogPath '${{ parameters.testLogPath }}'
|
||||
condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'x86')))
|
||||
|
||||
- task: PowerShell@2
|
||||
@@ -74,9 +81,41 @@ steps:
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: -MatchPattern '*feature.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)'
|
||||
arguments: -MatchPattern '*feature.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)' -LogPath '${{ parameters.testLogPath }}'
|
||||
condition: and(succeeded(), eq(variables['BuildPlatform'], 'x64'))
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Convert Test Logs from WTL to xUnit format'
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\ConvertWttLogToXUnit.ps1
|
||||
arguments: -WttInputPath '${{ parameters.testLogPath }}' -WttSingleRerunInputPath 'unused.wtl' -WttMultipleRerunInputPath 'unused2.wtl' -XUnitOutputPath 'onBuildMachineResults.xml' -TestNamePrefix '$(BuildConfiguration).$(BuildPlatform)'
|
||||
condition: or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'x86'))
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Upload converted test logs'
|
||||
inputs:
|
||||
testResultsFormat: 'xUnit' # Options: JUnit, NUnit, VSTest, xUnit, cTest
|
||||
testResultsFiles: '**/onBuildMachineResults.xml'
|
||||
#searchFolder: '$(System.DefaultWorkingDirectory)' # Optional
|
||||
#mergeTestResults: false # Optional
|
||||
#failTaskOnFailedTests: false # Optional
|
||||
testRunTitle: 'On Build Machine Tests' # Optional
|
||||
buildPlatform: $(BuildPlatform) # Optional
|
||||
buildConfiguration: $(BuildConfiguration) # Optional
|
||||
#publishRunAttachments: true # Optional
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy result logs to Artifacts'
|
||||
inputs:
|
||||
Contents: |
|
||||
**/*.wtl
|
||||
**/*onBuildMachineResults.xml
|
||||
${{ parameters.testLogPath }}
|
||||
TargetFolder: '$(Build.ArtifactStagingDirectory)/$(BuildConfiguration)/$(BuildPlatform)/test'
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy *.appx/*.msix to Artifacts (Non-PR builds only)'
|
||||
inputs:
|
||||
@@ -90,9 +129,22 @@ steps:
|
||||
flattenFolders: true
|
||||
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact (appx) (Non-PR builds only)'
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy outputs needed for test runs to Artifacts'
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)/appx'
|
||||
ArtifactName: 'appx-$(BuildConfiguration)'
|
||||
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
|
||||
Contents: |
|
||||
$(Build.SourcesDirectory)/bin/$(BuildPlatform)/$(BuildConfiguration)/*.exe
|
||||
$(Build.SourcesDirectory)/bin/$(BuildPlatform)/$(BuildConfiguration)/*.dll
|
||||
$(Build.SourcesDirectory)/bin/$(BuildPlatform)/$(BuildConfiguration)/*.xml
|
||||
**/Microsoft.VCLibs.*.appx
|
||||
**/TestHostApp/*
|
||||
TargetFolder: '$(Build.ArtifactStagingDirectory)/$(BuildConfiguration)/$(BuildPlatform)/test'
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
condition: and(and(succeeded(), eq(variables['BuildPlatform'], 'x64')), ne(variables['Build.Reason'], 'PullRequest'))
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish All Build Artifacts'
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||
ArtifactName: 'drop'
|
||||
15
build/pipelines/templates/helix-createprojfile-steps.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
parameters:
|
||||
condition: ''
|
||||
testFilePath: ''
|
||||
outputProjFileName: ''
|
||||
testSuite: ''
|
||||
taefQuery: ''
|
||||
|
||||
steps:
|
||||
- task: powershell@2
|
||||
displayName: 'Create ${{ parameters.outputProjFileName }}'
|
||||
condition: ${{ parameters.condition }}
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\GenerateTestProjFile.ps1
|
||||
arguments: -TestFile '${{ parameters.testFilePath }}' -OutputProjFile '$(Build.ArtifactStagingDirectory)\${{ parameters.outputProjFileName }}' -JobTestSuiteName '${{ parameters.testSuite }}' -TaefPath '$(Build.SourcesDirectory)\build\Helix\packages\taef.redist.wlk.10.57.200731005-develop\build\Binaries\x86' -TaefQuery '${{ parameters.taefQuery }}'
|
||||
68
build/pipelines/templates/helix-processtestresults-job.yml
Normal file
@@ -0,0 +1,68 @@
|
||||
parameters:
|
||||
condition: 'succeededOrFailed()'
|
||||
dependsOn: ''
|
||||
rerunPassesRequiredToAvoidFailure: 5
|
||||
minimumExpectedTestsExecutedCount: 10
|
||||
checkJobAttempt: false
|
||||
pgoArtifact: ''
|
||||
|
||||
jobs:
|
||||
- job: ProcessTestResults
|
||||
condition: ${{ parameters.condition }}
|
||||
dependsOn: ${{ parameters.dependsOn }}
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
timeoutInMinutes: 120
|
||||
variables:
|
||||
helixOutputFolder: $(Build.SourcesDirectory)\HelixOutput
|
||||
|
||||
steps:
|
||||
- task: powershell@2
|
||||
displayName: 'UpdateUnreliableTests.ps1'
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\UpdateUnreliableTests.ps1
|
||||
arguments: -RerunPassesRequiredToAvoidFailure '${{ parameters.rerunPassesRequiredToAvoidFailure }}'
|
||||
|
||||
- task: powershell@2
|
||||
displayName: 'OutputTestResults.ps1'
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\OutputTestResults.ps1
|
||||
arguments: -MinimumExpectedTestsExecutedCount '${{ parameters.minimumExpectedTestsExecutedCount }}' -CheckJobAttempt $${{ parameters.checkJobAttempt }}
|
||||
|
||||
- task: powershell@2
|
||||
displayName: 'ProcessHelixFiles.ps1'
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
HelixAccessToken: $(HelixApiAccessToken)
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\ProcessHelixFiles.ps1
|
||||
arguments: -OutputFolder '$(helixOutputFolder)'
|
||||
|
||||
- ${{if ne(parameters.pgoArtifact, '') }}:
|
||||
- script: move /y $(helixOutputFolder)\PGO $(Build.ArtifactStagingDirectory)
|
||||
displayName: 'Move pgc files to PGO artifact'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Helix files'
|
||||
condition: succeededOrFailed()
|
||||
inputs:
|
||||
PathtoPublish: $(helixOutputFolder)
|
||||
artifactName: drop
|
||||
|
||||
- ${{if ne(parameters.pgoArtifact, '') }}:
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish pgc files'
|
||||
condition: succeededOrFailed()
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)\PGO\Release
|
||||
artifactName: ${{ parameters.pgoArtifact }}
|
||||
131
build/pipelines/templates/helix-runtests-job.yml
Normal file
@@ -0,0 +1,131 @@
|
||||
parameters:
|
||||
name: 'RunTestsInHelix'
|
||||
dependsOn: ''
|
||||
condition: ''
|
||||
testSuite: ''
|
||||
# If a Pipeline runs this template more than once, this parameter should be unique per build flavor to differentiate the
|
||||
# the different test runs:
|
||||
helixType: 'test/devtest'
|
||||
artifactName: 'drop'
|
||||
maxParallel: 4
|
||||
rerunPassesRequiredToAvoidFailure: 5
|
||||
taefQuery: ''
|
||||
# if 'useBuildOutputFromBuildId' is set, we will default to using a build from this pipeline:
|
||||
useBuildOutputFromPipeline: $(System.DefinitionId)
|
||||
matrix:
|
||||
# Release_x86:
|
||||
# buildPlatform: 'x86'
|
||||
# buildConfiguration: 'release'
|
||||
# openHelixTargetQueues: 'windows.10.amd64.client19h1.open.xaml'
|
||||
# closedHelixTargetQueues: 'windows.10.amd64.client19h1.xaml'
|
||||
Release_x64:
|
||||
buildPlatform: 'x64'
|
||||
buildConfiguration: 'release'
|
||||
openHelixTargetQueues: 'windows.10.amd64.client19h1.open.xaml'
|
||||
closedHelixTargetQueues: 'windows.10.amd64.client19h1.xaml'
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
dependsOn: ${{ parameters.dependsOn }}
|
||||
condition: ${{ parameters.condition }}
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
timeoutInMinutes: 120
|
||||
strategy:
|
||||
maxParallel: ${{ parameters.maxParallel }}
|
||||
matrix: ${{ parameters.matrix }}
|
||||
variables:
|
||||
artifactsDir: $(Build.SourcesDirectory)\Artifacts
|
||||
taefPath: $(Build.SourcesDirectory)\build\Helix\packages\taef.redist.wlk.10.57.200731005-develop\build\Binaries\$(buildPlatform)
|
||||
helixCommonArgs: '/binaryLogger:$(Build.SourcesDirectory)/${{parameters.name}}.$(buildPlatform).$(buildConfiguration).binlog /p:HelixBuild=$(Build.BuildId).$(buildPlatform).$(buildConfiguration) /p:Platform=$(buildPlatform) /p:Configuration=$(buildConfiguration) /p:HelixType=${{parameters.helixType}} /p:TestSuite=${{parameters.testSuite}} /p:ProjFilesPath=$(Build.ArtifactStagingDirectory) /p:rerunPassesRequiredToAvoidFailure=${{parameters.rerunPassesRequiredToAvoidFailure}}'
|
||||
|
||||
|
||||
steps:
|
||||
- task: CmdLine@1
|
||||
displayName: 'Display build machine environment variables'
|
||||
inputs:
|
||||
filename: 'set'
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: 'Use NuGet 5.2.0'
|
||||
inputs:
|
||||
versionSpec: 5.2.0
|
||||
|
||||
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
|
||||
displayName: 'NuGet restore build/Helix/packages.config'
|
||||
inputs:
|
||||
restoreSolution: build/Helix/packages.config
|
||||
feedsToUse: config
|
||||
nugetConfigPath: nuget.config
|
||||
restoreDirectory: packages
|
||||
|
||||
- task: DownloadBuildArtifacts@0
|
||||
condition:
|
||||
and(succeeded(),eq(variables['useBuildOutputFromBuildId'],''))
|
||||
inputs:
|
||||
artifactName: ${{ parameters.artifactName }}
|
||||
downloadPath: '$(artifactsDir)'
|
||||
|
||||
- task: DownloadBuildArtifacts@0
|
||||
condition:
|
||||
and(succeeded(),ne(variables['useBuildOutputFromBuildId'],''))
|
||||
inputs:
|
||||
buildType: specific
|
||||
buildVersionToDownload: specific
|
||||
project: $(System.TeamProjectId)
|
||||
pipeline: ${{ parameters.useBuildOutputFromPipeline }}
|
||||
buildId: $(useBuildOutputFromBuildId)
|
||||
artifactName: ${{ parameters.artifactName }}
|
||||
downloadPath: '$(artifactsDir)'
|
||||
|
||||
- task: CmdLine@1
|
||||
displayName: 'Display Artifact Directory payload contents'
|
||||
inputs:
|
||||
filename: 'dir'
|
||||
arguments: '/s $(artifactsDir)'
|
||||
|
||||
- task: powershell@2
|
||||
displayName: 'PrepareHelixPayload.ps1'
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\PrepareHelixPayload.ps1
|
||||
arguments: -Platform '$(buildPlatform)' -Configuration '$(buildConfiguration)' -ArtifactName '${{ parameters.artifactName }}'
|
||||
|
||||
- task: CmdLine@1
|
||||
displayName: 'Display Helix payload contents'
|
||||
inputs:
|
||||
filename: 'dir'
|
||||
arguments: '/s $(Build.SourcesDirectory)\HelixPayload'
|
||||
|
||||
- template: helix-createprojfile-steps.yml
|
||||
parameters:
|
||||
condition: and(succeeded(),ne('${{ parameters.testSuite }}','NugetTestSuite'))
|
||||
testFilePath: '$(artifactsDir)\${{ parameters.artifactName }}\$(buildConfiguration)\$(buildPlatform)\Test\TerminalApp.LocalTests.dll'
|
||||
outputProjFileName: 'RunTestsInHelix-TerminalAppLocalTests.proj'
|
||||
testSuite: '${{ parameters.testSuite }}'
|
||||
taefQuery: ${{ parameters.taefQuery }}
|
||||
|
||||
- template: helix-createprojfile-steps.yml
|
||||
parameters:
|
||||
condition: and(succeeded(),ne('${{ parameters.testSuite }}','NugetTestSuite'))
|
||||
testFilePath: '$(artifactsDir)\${{ parameters.artifactName }}\$(buildConfiguration)\$(buildPlatform)\Test\Conhost.UIA.Tests.dll'
|
||||
outputProjFileName: 'RunTestsInHelix-HostTestsUIA.proj'
|
||||
testSuite: '${{ parameters.testSuite }}'
|
||||
taefQuery: ${{ parameters.taefQuery }}
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish generated .proj files'
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)
|
||||
artifactName: ${{ parameters.artifactName }}
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Run tests in Helix (open queues)'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
inputs:
|
||||
command: custom
|
||||
projects: build\Helix\RunTestsInHelix.proj
|
||||
custom: msbuild
|
||||
arguments: '$(helixCommonArgs) /p:IsExternal=true /p:Creator=Terminal /p:HelixTargetQueues=$(openHelixTargetQueues)'
|
||||
|
||||
18
build/rules/Branding.targets
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<_WTBrandingPreprocessorToken Condition="'$(WindowsTerminalBranding)'=='Preview'">WT_BRANDING_PREVIEW</_WTBrandingPreprocessorToken>
|
||||
<_WTBrandingPreprocessorToken Condition="'$(WindowsTerminalBranding)'=='Release'">WT_BRANDING_RELEASE</_WTBrandingPreprocessorToken>
|
||||
<_WTBrandingPreprocessorToken Condition="'$(_WTBrandingPreprocessorToken)'==''">WT_BRANDING_DEV</_WTBrandingPreprocessorToken>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>$(_WTBrandingPreprocessorToken);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>$(_WTBrandingPreprocessorToken);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
15
build/scripts/Get-WttLog.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
[CmdLetBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$true, Position=0)][string]$BuildPlatform,
|
||||
[Parameter(Mandatory=$true, Position=1)][string]$RationalizedPlatform,
|
||||
[Parameter(Mandatory=$true, Position=2)][string]$Configuration
|
||||
)
|
||||
|
||||
|
||||
$i = Get-Item .\packages\MuxCustomBuild*
|
||||
$wtt = Join-Path -Path $i[0].FullName -ChildPath (Join-Path -Path 'tools' -ChildPath (Join-Path -Path $BuildPlatform -ChildPath 'wttlog.dll'))
|
||||
$dest = Join-Path -Path .\bin -ChildPath (Join-Path -Path $RationalizedPlatform -ChildPath ($Configuration))
|
||||
copy $wtt $dest
|
||||
|
||||
|
||||
Exit 0
|
||||
@@ -2,12 +2,24 @@
|
||||
Param(
|
||||
[Parameter(Mandatory=$true, Position=0)][string]$MatchPattern,
|
||||
[Parameter(Mandatory=$true, Position=1)][string]$Platform,
|
||||
[Parameter(Mandatory=$true, Position=2)][string]$Configuration
|
||||
[Parameter(Mandatory=$true, Position=2)][string]$Configuration,
|
||||
[Parameter(Mandatory=$false, Position=3)][string]$LogPath
|
||||
)
|
||||
|
||||
$testdlls = Get-ChildItem -Path ".\bin\$Platform\$Configuration" -Recurse -Filter $MatchPattern
|
||||
|
||||
&".\bin\$Platform\$Configuration\te.exe" $testdlls.FullName
|
||||
|
||||
$args = @();
|
||||
|
||||
if ($LogPath)
|
||||
{
|
||||
$args += '/enablewttlogging';
|
||||
$args += '/appendwttlogging';
|
||||
$args += "/logFile:$LogPath";
|
||||
Write-Host "Wtt Logging Enabled";
|
||||
}
|
||||
|
||||
&".\bin\$Platform\$Configuration\te.exe" $args $testdlls.FullName
|
||||
|
||||
if ($lastexitcode -Ne 0) { Exit $lastexitcode }
|
||||
|
||||
|
||||
@@ -106,6 +106,10 @@ Try {
|
||||
Throw "Failed to find wt.exe/wtd.exe -- check the WAP packaging project"
|
||||
}
|
||||
|
||||
If ($null -eq (Get-Item "$AppxPackageRootPath\OpenConsole.exe" -EA:Ignore)) {
|
||||
Throw "Failed to find OpenConsole.exe -- check the WAP packaging project"
|
||||
}
|
||||
|
||||
} Finally {
|
||||
Remove-Item -Recurse -Force $AppxPackageRootPath
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2020</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>2</VersionMinor>
|
||||
<VersionMinor>5</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
19
doc/Niksa.md
@@ -9,6 +9,8 @@ This document serves as a storage point for those posts.
|
||||
- [Output Processing between "Far East" and "Western"](#fesb)
|
||||
- [Why do we not backport things?](#backport)
|
||||
- [Why can't we have mixed elevated and non-elevated tabs in the Terminal?](#elevation)
|
||||
- [What's the difference between a shell and a terminal?](#shell-vs-terminal)
|
||||
|
||||
|
||||
## <a name="cmd"></a>Why do we avoid changing CMD.exe?
|
||||
`setlocal` doesn't behave the same way as an environment variable. It's a thing that would have to be put in at the top of the batch script that is `somefile.cmd` as one of its first commands to adjust the way that one specific batch file is processed by the `cmd.exe` engine. That's probably not suitable for your needs, but that's the way we have to go.
|
||||
@@ -179,3 +181,20 @@ Other platforms have accepted that risk in preference for user convenience. They
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/632#issuecomment-519375707
|
||||
|
||||
## <a name="shell-vs-terminal"></a>What's the difference between a shell and a terminal?
|
||||
|
||||
_guest speaker @zadjii-msft_
|
||||
|
||||
I think there might be a bit of a misunderstanding here - there are two different kinds of applications we're talking about here:
|
||||
* shell applications, like `cmd.exe`, `powershell`, `zsh`, etc. These are text-only applications that emit streams of characters. They don't care at all about how they're eventually rendered to the user. These are also sometimes referred to as "commandline client" applications.
|
||||
* terminal applications, like the Windows Terminal, gnome-terminal, xterm, iterm2, hyper. These are graphical applications that can be used to render the output of commandline clients.
|
||||
|
||||
On Windows, if you just run `cmd.exe` directly, the OS will create an instance of `conhost.exe` as the _terminal_ for `cmd.exe`. The same thing happens for `powershell.exe`, the system will creates a new conhost window for any client that's not already connected to a terminal of some sort. This has lead to an enormous amount of confusion for people thinking that a conhost window is actually a "`cmd` window". `cmd` can't have a window, it's just a commandline application. Its window is always some other terminal.
|
||||
|
||||
Any terminal can run any commandline client application. So you can use the Windows Terminal to run whatever shell you want. I use mine for both `cmd` and `powershell`, and also WSL:
|
||||
|
||||

|
||||
|
||||
It's not the Terminal's responsibility to remember the commands executed by a commandline client. That's the responsibility of the _shell_. How would the terminal remember commands executed by something like `emacs` or `vim`? Those are both applications where the user is typing input and hitting enter, like they would at a cmd prompt, but without something that resembles a command history.
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/6500#issuecomment-670035468
|
||||
|
||||
38
doc/TAEF.md
@@ -1,9 +1,30 @@
|
||||
### TAEF ###
|
||||
### TAEF Overview ###
|
||||
|
||||
TAEF, the Test Authoring and Execution Framework, is used extensively within the Windows organization to test the operating system code in a unified manner for system, driver, and application code. As the console is a Windows OS Component, we strive to continue using the same system such that tests can be ran in a unified manner both externally to Microsoft as well as inside the official OS Build/Test system.
|
||||
|
||||
The [official documentation](https://msdn.microsoft.com/en-us/library/windows/hardware/hh439725\(v=vs.85\).aspx) for TAEF describes the basic architecture, usage, and functionality of the test system. It is similar to Visual Studio test, but a bit more comprehensive and flexible.
|
||||
The [official documentation](https://docs.microsoft.com/en-us/windows-hardware/drivers/taef/) for TAEF describes the basic architecture, usage, and functionality of the test system. It is similar to Visual Studio test, but a bit more comprehensive and flexible.
|
||||
|
||||
For the purposes of the console project, you can run the tests using the *TE.exe* that matches the architecture for which the test was build (x86/x64) in the pattern
|
||||
### Writing Tests
|
||||
|
||||
You may want to read the section [Authoring Tests in C++](https://docs.microsoft.com/en-us/windows-hardware/drivers/taef/authoring-tests-in-c--) before getting your hands dirty. Note that the quoted header name in `#include "WexTestClass.h"` might be a bit confusing. You are not required to copy TAEF headers into the project folder.
|
||||
|
||||
Use the [TAEF Verify Macros for C++](https://docs.microsoft.com/en-us/windows-hardware/drivers/taef/verify) in your test code to perform verifications.
|
||||
|
||||
### Running Tests
|
||||
|
||||
If you have Visual Studio and related C++ components installed, and you have successfully restored NuGets, you should have the TAEF test runner `te.exe` available locally as part of the `Taef.Redist.Wlk` package.
|
||||
|
||||
> Note that you cannot easily run TAEF tests directly through Visual Studio. The `Taef.Redist.Wlk` NuGet package comes with an adapter that will let you browse and execute TAEF tests inside of Visual Studio, but its performance and reliability prevent us from recommending it here.
|
||||
|
||||
In a "normal" CMD environment, `te.exe` may not be directly available. Try the following command to set up the development enviroment first:
|
||||
|
||||
```shell
|
||||
.\tools\razzle.cmd
|
||||
```
|
||||
|
||||
Then you should be able to use `%TAEF%` as an alias of the actual `te.exe`.
|
||||
|
||||
For the purposes of the OpenConsole project, you can run the tests using the `te.exe` that matches the architecture for which the test was built (x86/x64):
|
||||
|
||||
te.exe Console.Unit.Tests.dll
|
||||
|
||||
@@ -15,6 +36,15 @@ Limiting the tests to be run is also useful with:
|
||||
|
||||
Any pattern of class/method names can be specified after the */name:* flag with wildcard patterns.
|
||||
|
||||
For any further details on the functionality of the TAEF test runner, *TE.exe*, please see the documentation above or run the embedded help with
|
||||
For any further details on the functionality of the TAEF test runner, please see the [Executing Tests](https://docs.microsoft.com/en-us/windows-hardware/drivers/taef/executing-tests) section in the official documentation. Or run the embedded help with
|
||||
|
||||
te.exe /!
|
||||
|
||||
If you use PowerShell, try the following command:
|
||||
|
||||
```powershell
|
||||
Import-Module .\tools\OpenConsole.psm1
|
||||
Invoke-OpenConsoleTests
|
||||
```
|
||||
|
||||
`Invoke-OpenConsoleTests` supports a number of options, which you can enumerate by running `Invoke-OpenConsoleTests -?`.
|
||||
|
||||
@@ -67,12 +67,12 @@ To update the version of a given package, use the following snippet
|
||||
|
||||
where:
|
||||
- `$PackageName` is the name of the package, e.g. Microsoft.UI.Xaml
|
||||
- `$OldVersionNumber` is the version number currently used, e.g. 2.5.0-prerelease.200609001
|
||||
- `$NewVersionNumber` is the version number you want to migrate to, e.g. 2.4.200117003-prerelease
|
||||
- `$OldVersionNumber` is the version number currently used, e.g. 2.4.0-prerelease.200506002
|
||||
- `$NewVersionNumber` is the version number you want to migrate to, e.g. 2.5.0-prerelease.200812002
|
||||
|
||||
Example usage:
|
||||
|
||||
`git grep -z -l Microsoft.UI.Xaml | xargs -0 sed -i -e 's/2.5.0-prerelease.200609001/2.4.200117003-prerelease/g'`
|
||||
`git grep -z -l Microsoft.UI.Xaml | xargs -0 sed -i -e 's/2.4.0-prerelease.200506002/2.5.0-prerelease.200812002/g'`
|
||||
|
||||
## Using .nupkg files instead of downloaded Nuget packages
|
||||
If you want to use .nupkg files instead of the downloaded Nuget package, you can do this with the following steps:
|
||||
|
||||
@@ -1,210 +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 | `false` | 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. |
|
||||
| `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> /\()"'-:,.;<>~!@#$%^&*|+=[]{}~?│</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"` ( ▃ ), `"bar"` ( ┃ ), `"underscore"` ( ▁ ), `"filledBox"` ( █ ), `"emptyBox"` ( ▯ ) |
|
||||
| `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. | `singleLine` | boolean | When `true`, the copied content will be copied as a single line. When `false`, newlines persist from the selected text. |
|
||||
| `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. | | | |
|
||||
| `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` |
|
||||
| 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:
|
||||
|
||||

|
||||
⚠ This document has moved to [the Customize Settings section of the Windows Terminal documentation](https://docs.microsoft.com/windows/terminal/customize-settings/global-settings).
|
||||
|
||||
@@ -86,7 +86,7 @@ project from our `TerminalAppLib` project:
|
||||
duplicate type definitions)-->
|
||||
|
||||
<Reference Include="Microsoft.Terminal.Settings">
|
||||
<HintPath>$(SolutionDir)$(Platform)\$(Configuration)\TerminalSettings\Microsoft.Terminal.Settings.winmd</HintPath>
|
||||
<HintPath>$(OpenConsoleCommonOutDir)\TerminalSettings\Microsoft.Terminal.Settings.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
@@ -122,7 +122,7 @@ dir to your `AdditionalLibraryDirectories`, and adding the lib to your
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<!-- Manually link with the TerminalAppLib.lib we've built. -->
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)\$(Platform)\$(Configuration)\TerminalAppLib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(OpenConsoleCommonOutDir)\TerminalAppLib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
||||
<AdditionalDependencies>TerminalAppLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
@@ -260,9 +260,9 @@ this:
|
||||
echo OutDir=$(OutDir)
|
||||
(xcopy /Y "$(SolutionDir)src\cascadia\ut_app\TerminalApp.Unit.Tests.manifest" "$(OutDir)\TerminalApp.Unit.Tests.manifest*" )
|
||||
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalConnection\TerminalConnection.dll" "$(OutDir)\TerminalConnection.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalSettings\TerminalSettings.dll" "$(OutDir)\TerminalSettings.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalControl\TerminalControl.dll" "$(OutDir)\TerminalControl.dll*" )
|
||||
(xcopy /Y "$(OpenConsoleCommonOutDir)\TerminalConnection\TerminalConnection.dll" "$(OutDir)\TerminalConnection.dll*" )
|
||||
(xcopy /Y "$(OpenConsoleCommonOutDir)\TerminalSettings\TerminalSettings.dll" "$(OutDir)\TerminalSettings.dll*" )
|
||||
(xcopy /Y "$(OpenConsoleCommonOutDir)\TerminalControl\TerminalControl.dll" "$(OutDir)\TerminalControl.dll*" )
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -446,9 +446,9 @@ before. The complete `PostBuildEvent` now looks like this:
|
||||
|
||||
(xcopy /Y "$(SolutionDir)src\cascadia\ut_app\TerminalApp.Unit.Tests.AppxManifest.xml" "$(OutDir)\TerminalApp.Unit.Tests.AppxManifest.xml*" )
|
||||
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalConnection\TerminalConnection.dll" "$(OutDir)\TerminalConnection.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalSettings\TerminalSettings.dll" "$(OutDir)\TerminalSettings.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalControl\TerminalControl.dll" "$(OutDir)\TerminalControl.dll*" )
|
||||
(xcopy /Y "$(OpenConsoleCommonOutDir)\TerminalConnection\TerminalConnection.dll" "$(OutDir)\TerminalConnection.dll*" )
|
||||
(xcopy /Y "$(OpenConsoleCommonOutDir)\TerminalSettings\TerminalSettings.dll" "$(OutDir)\TerminalSettings.dll*" )
|
||||
(xcopy /Y "$(OpenConsoleCommonOutDir)\TerminalControl\TerminalControl.dll" "$(OutDir)\TerminalControl.dll*" )
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"$id": "https://github.com/microsoft/terminal/blob/master/doc/cascadia/profiles.schema.json",
|
||||
"$id": "https://github.com/microsoft/terminal/blob/main/doc/cascadia/profiles.schema.json",
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema#",
|
||||
"title": "Microsoft's Windows Terminal Settings Profile Schema",
|
||||
"definitions": {
|
||||
"KeyChordSegment": {
|
||||
"pattern": "^(?<modifier>(ctrl|alt|shift)(?:\\+(ctrl|alt|shift)(?<!\\2))?(?:\\+(ctrl|alt|shift)(?<!\\2|\\3))?\\+)?(?<key>[^\\s+]|backspace|tab|enter|esc|escape|space|pgup|pageup|pgdn|pagedown|end|home|left|up|right|down|insert|delete|(?<!shift.+)(?:numpad_?[0-9]|numpad_(?:period|decimal))|numpad_(?:multiply|plus|add|minus|subtract|divide)|f[1-9]|f1[0-9]|f2[0-4]|plus)$",
|
||||
"pattern": "^(?<modifier>(ctrl|alt|shift)(?:\\+(ctrl|alt|shift)(?<!\\2))?(?:\\+(ctrl|alt|shift)(?<!\\2|\\3))?\\+)?(?<key>[^\\s+]|app|menu|backspace|tab|enter|esc|escape|space|pgup|pageup|pgdn|pagedown|end|home|left|up|right|down|insert|delete|(?<!shift.+)(?:numpad_?[0-9]|numpad_(?:period|decimal))|numpad_(?:multiply|plus|add|minus|subtract|divide)|f[1-9]|f1[0-9]|f2[0-4]|plus)$",
|
||||
"type": "string",
|
||||
"description": "The string should fit the format \"[ctrl+][alt+][shift+]<keyName>\", where each modifier is optional, separated by + symbols, and keyName is either one of the names listed in the table below, or any single key character. The string should be written in full lowercase.\nbackspace\tBACKSPACE key\ntab\tTAB key\nenter\tENTER key\nesc, escape\tESC key\nspace\tSPACEBAR\npgup, pageup\tPAGE UP key\npgdn, pagedown\tPAGE DOWN key\nend\tEND key\nhome\tHOME key\nleft\tLEFT ARROW key\nup\tUP ARROW key\nright\tRIGHT ARROW key\ndown\tDOWN ARROW key\ninsert\tINS key\ndelete\tDEL key\nnumpad_0-numpad_9, numpad0-numpad9\tNumeric keypad keys 0 to 9. Can't be combined with the shift modifier.\nnumpad_multiply\tNumeric keypad MULTIPLY key (*)\nnumpad_plus, numpad_add\tNumeric keypad ADD key (+)\nnumpad_minus, numpad_subtract\tNumeric keypad SUBTRACT key (-)\nnumpad_period, numpad_decimal\tNumeric keypad DECIMAL key (.). Can't be combined with the shift modifier.\nnumpad_divide\tNumeric keypad DIVIDE key (/)\nf1-f24\tF1 to F24 function keys\nplus\tADD key (+)"
|
||||
"description": "The string should fit the format \"[ctrl+][alt+][shift+]<keyName>\", where each modifier is optional, separated by + symbols, and keyName is either one of the names listed in the table below, or any single key character. The string should be written in full lowercase.\napp, menu\tMENU key\nbackspace\tBACKSPACE key\ntab\tTAB key\nenter\tENTER key\nesc, escape\tESC key\nspace\tSPACEBAR\npgup, pageup\tPAGE UP key\npgdn, pagedown\tPAGE DOWN key\nend\tEND key\nhome\tHOME key\nleft\tLEFT ARROW key\nup\tUP ARROW key\nright\tRIGHT ARROW key\ndown\tDOWN ARROW key\ninsert\tINS key\ndelete\tDEL key\nnumpad_0-numpad_9, numpad0-numpad9\tNumeric keypad keys 0 to 9. Can't be combined with the shift modifier.\nnumpad_multiply\tNumeric keypad MULTIPLY key (*)\nnumpad_plus, numpad_add\tNumeric keypad ADD key (+)\nnumpad_minus, numpad_subtract\tNumeric keypad SUBTRACT key (-)\nnumpad_period, numpad_decimal\tNumeric keypad DECIMAL key (.). Can't be combined with the shift modifier.\nnumpad_divide\tNumeric keypad DIVIDE key (/)\nf1-f24\tF1 to F24 function keys\nplus\tADD key (+)"
|
||||
},
|
||||
"Color": {
|
||||
"default": "#",
|
||||
@@ -26,43 +26,65 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"BellStyle": {
|
||||
"enum": [
|
||||
"none",
|
||||
"audible"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ProfileGuid": {
|
||||
"default": "{}",
|
||||
"pattern": "^\\{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\}$",
|
||||
"type": "string"
|
||||
},
|
||||
"Icon": {
|
||||
"description": "Image file location or an emoji to be used as an icon. Displays within the tab, the dropdown menu, and jumplist.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"ShortcutActionName": {
|
||||
"enum": [
|
||||
"adjustFontSize",
|
||||
"closeOtherTabs",
|
||||
"closePane",
|
||||
"closeTab",
|
||||
"closeTabsAfter",
|
||||
"closeWindow",
|
||||
"commandPalette",
|
||||
"copy",
|
||||
"duplicateTab",
|
||||
"find",
|
||||
"moveFocus",
|
||||
"newTab",
|
||||
"nextTab",
|
||||
"openNewTabDropdown",
|
||||
"openSettings",
|
||||
"openTabColorPicker",
|
||||
"paste",
|
||||
"prevTab",
|
||||
"renameTab",
|
||||
"openTabRenamer",
|
||||
"resetFontSize",
|
||||
"resizePane",
|
||||
"scrollDown",
|
||||
"scrollDownPage",
|
||||
"scrollUp",
|
||||
"scrollUpPage",
|
||||
"sendInput",
|
||||
"setColorScheme",
|
||||
"setTabColor",
|
||||
"splitPane",
|
||||
"switchToTab",
|
||||
"tabSearch",
|
||||
"toggleAlwaysOnTop",
|
||||
"toggleFocusMode",
|
||||
"toggleFullscreen",
|
||||
"toggleAlwaysOnTop",
|
||||
"togglePaneZoom",
|
||||
"toggleRetroEffect",
|
||||
"find",
|
||||
"setTabColor",
|
||||
"openTabColorPicker",
|
||||
"renameTab",
|
||||
"commandPalette",
|
||||
"wt",
|
||||
"unbound"
|
||||
],
|
||||
"type": "string"
|
||||
@@ -84,6 +106,40 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"CopyFormat": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"html",
|
||||
"rtf"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"html",
|
||||
"rtf",
|
||||
"all",
|
||||
"none"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"AnchorKey": {
|
||||
"enum": [
|
||||
"ctrl",
|
||||
"alt",
|
||||
"shift"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"NewTerminalArgs": {
|
||||
"properties": {
|
||||
"commandline": {
|
||||
@@ -149,6 +205,18 @@
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If true, the copied content will be copied as a single line (even if there are hard line breaks present in the text). If false, newlines persist from the selected text."
|
||||
},
|
||||
"copyFormatting": {
|
||||
"default": null,
|
||||
"description": "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.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/CopyFormat"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,6 +285,28 @@
|
||||
],
|
||||
"required": [ "direction" ]
|
||||
},
|
||||
"SendInputAction": {
|
||||
"description": "Arguments corresponding to a Send Input Action",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"pattern": "sendInput"
|
||||
},
|
||||
"input": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "The text input to feed into the shell. ANSI escape sequences may be used. Escape codes like \\x1b must be written as \\u001b."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "input" ]
|
||||
},
|
||||
"SplitPaneAction": {
|
||||
"description": "Arguments corresponding to a Split Pane Action",
|
||||
"allOf": [
|
||||
@@ -280,6 +370,110 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"SetColorSchemeAction": {
|
||||
"description": "Arguments corresponding to a Set Color Scheme Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "setColorScheme" },
|
||||
"colorScheme": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "the name of the scheme to apply to the active pane"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "colorScheme" ]
|
||||
},
|
||||
"WtAction": {
|
||||
"description": "Arguments corresponding to a wt Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "wt" },
|
||||
"commandline": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "a `wt` commandline to run in the current window"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "commandline" ]
|
||||
},
|
||||
"CloseOtherTabsAction": {
|
||||
"description": "Arguments for a closeOtherTabs action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "closeOtherTabs" },
|
||||
"index": {
|
||||
"oneOf": [
|
||||
{ "type": "integer" },
|
||||
{ "type": null }
|
||||
],
|
||||
"default": "",
|
||||
"description": "Close the tabs other than the one at this index. If no index is provided, use the focused tab's index."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"CloseTabsAfterAction": {
|
||||
"description": "Arguments for a closeTabsAfter action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "closeTabsAfter" },
|
||||
"index": {
|
||||
"oneOf": [
|
||||
{ "type": "integer" },
|
||||
{ "type": null }
|
||||
],
|
||||
"default": "",
|
||||
"description": "Close the tabs following the tab at this index. If no index is provided, use the focused tab's index."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ScrollUpAction": {
|
||||
"description": "Arguments for a scrollUp action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "scrollUp" },
|
||||
"rowsToScroll": {
|
||||
"type": ["integer", "null"],
|
||||
"default": null,
|
||||
"description": "Scroll up rowsToScroll lines. If no value is provided, use the system-level defaults."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ScrollDownAction": {
|
||||
"description": "Arguments for a scrollDown action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "scrollDown" },
|
||||
"rowsToScroll": {
|
||||
"type": ["integer", "null"],
|
||||
"default": null,
|
||||
"description": "Scroll down rowsToScroll lines. If no value is provided, use the system-level defaults."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Keybinding": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -293,9 +487,16 @@
|
||||
{ "$ref": "#/definitions/SwitchToTabAction" },
|
||||
{ "$ref": "#/definitions/MoveFocusAction" },
|
||||
{ "$ref": "#/definitions/ResizePaneAction" },
|
||||
{ "$ref": "#/definitions/SendInputAction" },
|
||||
{ "$ref": "#/definitions/SplitPaneAction" },
|
||||
{ "$ref": "#/definitions/OpenSettingsAction" },
|
||||
{ "$ref": "#/definitions/SetTabColorAction" },
|
||||
{ "$ref": "#/definitions/SetColorSchemeAction" },
|
||||
{ "$ref": "#/definitions/WtAction" },
|
||||
{ "$ref": "#/definitions/CloseOtherTabsAction" },
|
||||
{ "$ref": "#/definitions/CloseTabsAfterAction" },
|
||||
{ "$ref": "#/definitions/ScrollUpAction" },
|
||||
{ "$ref": "#/definitions/ScrollDownAction" },
|
||||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
@@ -313,6 +514,14 @@
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"icon": { "$ref": "#/definitions/Icon" },
|
||||
"name": {
|
||||
"description": "The name that will appear in the command palette. If one isn't provided, the terminal will attempt to automatically generate a name.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -342,7 +551,12 @@
|
||||
},
|
||||
"copyFormatting": {
|
||||
"default": true,
|
||||
"description": "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.",
|
||||
"description": "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.",
|
||||
"$ref": "#/definitions/CopyFormat"
|
||||
},
|
||||
"disableAnimations": {
|
||||
"default": false,
|
||||
"description": "When set to `true`, visual animations will be disabled across the application.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"largePasteWarning": {
|
||||
@@ -376,28 +590,36 @@
|
||||
},
|
||||
"initialCols": {
|
||||
"default": 120,
|
||||
"description": "The number of columns displayed in the window upon first load.",
|
||||
"description": "The number of columns displayed in the window upon first load. If \"launchMode\" is set to \"maximized\" (or \"maximizedFocus\"), this property is ignored.",
|
||||
"maximum": 999,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"initialPosition": {
|
||||
"$ref": "#/definitions/Coordinates",
|
||||
"description": "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."
|
||||
"description": "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\" (or \"maximizedFocus\"), the window will be maximized on the monitor specified by those coordinates."
|
||||
},
|
||||
"initialRows": {
|
||||
"default": 30,
|
||||
"description": "The number of rows displayed in the window upon first load.",
|
||||
"description": "The number of rows displayed in the window upon first load. If \"launchMode\" is set to \"maximized\" (or \"maximizedFocus\"), this property is ignored.",
|
||||
"maximum": 999,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"startOnUserLogin": {
|
||||
"default": false,
|
||||
"description": "When set to true, this enables the launch of Windows Terminal at startup. Setting this to false will disable the startup task entry. If the Windows Terminal startup task entry is disabled either by org policy or by user action this setting will have no effect.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"launchMode": {
|
||||
"default": "default",
|
||||
"description": "Defines whether the Terminal will launch as maximized or not.",
|
||||
"description": "Defines whether the terminal will launch as maximized, full screen, or in a window. Setting this to \"focus\" is equivalent to launching the terminal in the \"default\" mode, but with the focus mode enabled. Similar, setting this to \"maximizedFocus\" will result in launching the terminal in a maximized window with the focus mode enabled.",
|
||||
"enum": [
|
||||
"fullscreen",
|
||||
"maximized",
|
||||
"default"
|
||||
"default",
|
||||
"focus",
|
||||
"maximizedFocus"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -460,6 +682,11 @@
|
||||
"default": true,
|
||||
"description": "When set to \"true\" closing a window with multiple tabs open will require confirmation. When set to \"false\", the confirmation dialog will not appear.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"useTabSwitcher": {
|
||||
"default": true,
|
||||
"description": "When set to \"true\", the \"nextTab\" and \"prevTab\" commands will use the tab switcher UI.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -532,6 +759,11 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"bellStyle": {
|
||||
"default": "audible",
|
||||
"description": "Controls what happens when the application emits a BEL character. When set to \"audible\", the Terminal will play a sound. When set to \"none\", nothing will happen.",
|
||||
"$ref": "#/definitions/BellStyle"
|
||||
},
|
||||
"closeOnExit": {
|
||||
"default": "graceful",
|
||||
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",
|
||||
@@ -647,10 +879,7 @@
|
||||
"minimum": -1,
|
||||
"type": "integer"
|
||||
},
|
||||
"icon": {
|
||||
"description": "Image file location of the icon used in the profile. Displays within the tab and the dropdown menu.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"icon":{ "$ref": "#/definitions/Icon" },
|
||||
"name": {
|
||||
"description": "Name of the profile. Displays in the dropdown menu.",
|
||||
"minLength": 1,
|
||||
@@ -659,8 +888,15 @@
|
||||
"padding": {
|
||||
"default": "8, 8, 8, 8",
|
||||
"description": "Sets the padding around the text within the window. Can have three different formats:\n -\"#\" sets the same padding for all sides \n -\"#, #\" sets the same padding for left-right and top-bottom\n -\"#, #, #, #\" sets the padding individually for left, top, right, and bottom.",
|
||||
"pattern": "^-?[0-9]+(\\.[0-9]+)?( *, *-?[0-9]+(\\.[0-9]+)?|( *, *-?[0-9]+(\\.[0-9]+)?){3})?$",
|
||||
"type": "string"
|
||||
"oneOf": [
|
||||
{
|
||||
"pattern": "^-?[0-9]+(\\.[0-9]+)?( *, *-?[0-9]+(\\.[0-9]+)?|( *, *-?[0-9]+(\\.[0-9]+)?){3})?$",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scrollbarState": {
|
||||
"default": "visible",
|
||||
|
||||
54
doc/creating_a_new_project.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Creating a New Project
|
||||
|
||||
## Creating a new WinRT Component DLL and referencing it in another project
|
||||
|
||||
When creating a new DLL, it was really helpful to reference an existing DLL's `.vcxproj` like `TerminalControl.vcxproj`. While you should mostly try to copy what the existing `.vcxproj` has, here's a handful of things to double check for as you go along.
|
||||
|
||||
- [ ] Make sure to `<Import>` our pre props at the _top_ of the vcxproj, and our post props at the _bottom_ of the vcxproj.
|
||||
```
|
||||
<!-- pre props -->
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<!-- everything else -->
|
||||
|
||||
<!-- post props -->
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
```
|
||||
- [ ] Add a `<ProjectReference>` to your new `.vcxproj` in both `WindowsTerminal.vcxproj` and `TerminalApp.vcxproj`
|
||||
- [ ] Add a `<Reference>` to `TerminalAppLib.vcxproj` similar to this:
|
||||
```
|
||||
<Reference Include="Microsoft.Terminal.NewDLL">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)\TerminalNewDLL\Microsoft.Terminal.NewDLL.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
```
|
||||
- [ ] Make sure the project has a `.def` file with the following lines. The `WINRT_GetActivationFactory` part is important to expose the new DLL's activation factory so that other projects can successfully call the DLL's `GetActivationFactory` to get the DLL's classes.
|
||||
```
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
```
|
||||
- For a bit more context on this whole process, the `AppXManifest.xml` file defines which classes belong to which DLLs. If your project wants class `X.Y.Z`, it can look it up in the manifest's definitions and see that it came from `X.Y.dll`. Then it'll load up the DLL, and call a particular function called `GetActivationFactory(L"X.Y.Z")` to get the class it wants. So, the definitions in `AppXManifest` are _required_ for this activation to work properly, and I found myself double checking the file to see that the definitions I expect are there.
|
||||
- _Note_: If your new library eventually rolls up as a reference to our Centennial Packaging project `CascadiaPackage`, you don't have to worry about manually adding your definitions to the `AppXManifest.xml` because the Centennial Packaging project automatically enumerates the reference tree of WinMDs and stitches that information into the `AppXManifest.xml`. However, if your new project does _not_ ultimately roll up to a packaging project that will automatically put the references into `AppXManifest`, you will have to add them in manually.
|
||||
|
||||
### Troubleshooting
|
||||
- If you hit an error that looks like this:
|
||||
```
|
||||
X found processing metadata file ..\blah1\Microsoft.UI.Xaml.winmd, type already exists in file ..\blah\NewDLLProject\Microsoft.UI.Xaml.winmd.
|
||||
```
|
||||
The `Microsoft.UI.Xaml.winmd` is showing up in the output folder when it shouldn't. Try adding this block at the top of your `.vcxproj`
|
||||
```
|
||||
<ItemDefinitionGroup>
|
||||
<Reference>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemDefinitionGroup>
|
||||
```
|
||||
This will make all references non-private, meaning "don't copy it into my folder" by default.
|
||||
|
||||
- If you hit a `Class not Registered` error, this might be because a class isn't getting registered in the app manifest. You can go check `src/cascadia/CascadiaPackage/bin/x64/Debug/AppX/AppXManifest.xml` to see if there exist entries to the classes of your newly created DLL. If the references aren't there, double check that you've added `<ProjectReference>` blocks to both `WindowsTerminal.vcxproj` and `TerminalApp.vcxproj`.
|
||||
|
||||
- If you hit an extremely vague error along the lines of `Error in the DLL`, and right before that line you notice that your new DLL is loaded and unloaded right after each other, double check that your new DLL's definitions show up in the `AppXManifest.xml` file. If your new DLL is included as a reference to a project that rolls up to `CascadiaPackage`, double check that you've created a `.def` file for the project. Otherwise if your new project _does not_ roll up to a package that populates the `AppXManifest` references for you, you'll have to add those references yourself.
|
||||
|
Before Width: | Height: | Size: 135 KiB |
@@ -0,0 +1,146 @@
|
||||
---
|
||||
author: Mike Griese @zadjii-msft
|
||||
created on: 2020-07-31
|
||||
last updated: 2020-08-03
|
||||
issue id: #1337
|
||||
---
|
||||
# Per-Profile Tab Colors
|
||||
|
||||
## Abstract
|
||||
|
||||
This spec describes a way to specify tab colors in a profile in a way that will
|
||||
be forward compatible with theming the Terminal. This spec will be largely
|
||||
dedicated to the design of a single setting, but within the context of theming.
|
||||
|
||||
## Inspiration
|
||||
|
||||
Following the addition of the Tab Color Picker in [#3789], we've had numerous
|
||||
requests for the ability to set the color of a tab directly within a profile.
|
||||
While largely we're tracking theming in [#3327], including the specification of
|
||||
a tab color, the theming spec ([#5772] )is very large and will take a while to
|
||||
revise and approve. This spec is intended to pull a single point out from that
|
||||
spec to make it more easily reviewable, and implement it in a way that will
|
||||
continue working when we add support for themes in the future.
|
||||
|
||||
## Solution Design
|
||||
|
||||
To enable per-profile tab colors, we'll add a single setting: `tabColor`. For
|
||||
now<sup>[[1](#user-content-footnote-1)]</sup>, this setting will accept any
|
||||
`#rrggbb` color string.
|
||||
|
||||
Since each profile creates a `Pane` with a `TermControl`, we'll need to store
|
||||
this color not in the `Tab`, but somewhere below `Pane`, so that when you switch
|
||||
between Panes in a tab with different `tabColor`s, the color will update
|
||||
automatically. When a new `TermControl` is created, we'll store this color in the
|
||||
`TermControl`'s `Terminal` core. This is to support the future possibility of
|
||||
setting the tab color via VT sequences.
|
||||
|
||||
A Tab's color will be the result of layering a variety of sources, from the bottom up:
|
||||
|
||||
Color | | Set by
|
||||
-- | -- | --
|
||||
Runtime Color | _optional_ |Color Picker / `setTabColor` action
|
||||
Control Tab Color | _optional_ | Profile's `tabColor`, or a color set by VT
|
||||
Theme Tab Background | _optional_ | `tab.backgroundColor` in the theme
|
||||
Tab Default Color | **default** | TabView in XAML
|
||||
|
||||
Some examples:
|
||||
* **Scenario 1**: The user has set `"tabColor": "#ff0000"` in their profile.
|
||||
When they create tabs with that profile, instead of appearing in the default
|
||||
color for the TabView, they'll be `#ff0000`.
|
||||
* **Scenario 2**: The user has set `"tabColor": "#ff0000"` in their profile.
|
||||
When they try to set the color for that tab (with the color picker) to
|
||||
`#0000ff`, the tab's color is updated to reflect this new blue color. When
|
||||
they clear the runtime color (with the color picker), the tab will return to
|
||||
`#ff0000`.
|
||||
* **Scenario 3**: The user has two profiles with colors set, one to `"tabColor":
|
||||
"#ff0000"`, and the other with `"tabColor": "#00ff00"`. If they open these
|
||||
profiles in two panes side-by side, the tab's color will update to reflect the
|
||||
color from the currently-focused control.
|
||||
* **Scenario 4**: The user has two profiles with colors set, one to `"tabColor":
|
||||
"#ff0000"`, and the other with `"tabColor": "#00ff00"`. If they open these
|
||||
profiles in two panes side-by side, and try to set the color for that tab
|
||||
(with the color picker) to `#0000ff`, the tab's color is updated to reflect
|
||||
this new blue color. Regardless of which pane is focused, the tab will be
|
||||
blue.
|
||||
* **Scenario 5**: The user has set `"tabColor": "#ff0000"` in their profile
|
||||
("Profile A"), and `"tab.backgroundColor": "#00ff00"`in their theme. When they
|
||||
create tabs with "Profile A", the tabs will appear red. Other tabs (for
|
||||
profiles without `tabColor` set) will appear green, using the color from the
|
||||
theme.
|
||||
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
In general, this is going to look exactly like the colored tabs look now.
|
||||
|
||||

|
||||
|
||||
## Capabilities
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Accessibility</strong></td>
|
||||
<td>
|
||||
N/A
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Security</strong></td>
|
||||
<td>
|
||||
N/A
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Reliability</strong></td>
|
||||
<td>
|
||||
No expected change
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Compatibility</strong></td>
|
||||
<td>
|
||||
This entire spec outlines how this feature is designed with a emphasis on future
|
||||
compatibility. As such, there are no expected regressions in the future when we
|
||||
do add support for themes.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Performance, Power, and Efficiency</strong></td>
|
||||
<td>
|
||||
No expected change
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Potential Issues
|
||||
|
||||
None expected.
|
||||
|
||||
## Footnotes
|
||||
|
||||
<a id="footnote-1"><a>[1]: When full theming support is added, themes will
|
||||
provide support for setting colors as one of a variety of values:
|
||||
|
||||
* An `#rrggbb` string
|
||||
* The system accent color
|
||||
* The current background color of the Terminal
|
||||
* A value from a given resource key from XAML
|
||||
|
||||
When support for these other types of "smart" colors is added, then the profile
|
||||
`tabColor` setting will also gracefully accept these values.
|
||||
|
||||
## Future considerations
|
||||
|
||||
* It's not out of the realm of possibility that someone might want to color each
|
||||
_pane_'s color at runtime. In that case, the runtime color would be stored in
|
||||
the `Pane`, not the `Tab`.
|
||||
|
||||
|
||||
|
||||
<!-- Footnotes -->
|
||||
|
||||
[#1337]: https://github.com/microsoft/terminal/issues/1337
|
||||
[#3789]: https://github.com/microsoft/terminal/issues/3789
|
||||
[#3327]: https://github.com/microsoft/terminal/issues/3327
|
||||
[#5772]: https://github.com/microsoft/terminal/pull/5772
|
||||
|
After Width: | Height: | Size: 816 KiB |
BIN
doc/specs/#1564 - Settings UI/appearance.png
Normal file
|
After Width: | Height: | Size: 274 KiB |
112
doc/specs/#1564 - Settings UI/design.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
author: Kayla Cinnamon @cinnamon-msft
|
||||
created on: 2020-07-13
|
||||
last updated: 2020-08-11
|
||||
issue id: #1564
|
||||
---
|
||||
|
||||
# Settings UI Design
|
||||
|
||||
## Abstract
|
||||
|
||||
This design document describes how each page of the settings UI will be laid out along with design mockups to display how the UI will appear. The mock ups are for appearance purposes and some layouts and naming may be different in this doc. This doc should be considered the final say.
|
||||
|
||||
## UI Design
|
||||
|
||||
### Overall navigation with Startup page
|
||||
|
||||
This is the list of the top-level navigation items that will appear on the left nav bar:
|
||||
|
||||
- General
|
||||
- Startup
|
||||
- Interaction
|
||||
- Rendering
|
||||
- Appearance
|
||||
- Global
|
||||
- Color schemes
|
||||
- Themes*
|
||||
- Profiles
|
||||
- Defaults
|
||||
- Enumerate profiles
|
||||
- Add new
|
||||
- Keyboard
|
||||
- Mouse*
|
||||
- Command Palette*
|
||||
- Marketplace*
|
||||
|
||||
\* Themes, mouse, command palette, and marketplace will be added once they're implemented.
|
||||
|
||||

|
||||
|
||||
### Profile appearance page
|
||||
|
||||
This page requires special design because it includes the TerminalControl window to preview appearance changes. This preview window will appear on the following pages:
|
||||
|
||||
- Appearance - Color Schemes
|
||||
- Profiles - Appearance
|
||||
|
||||

|
||||
|
||||
### Keyboard page
|
||||
|
||||
The keyboard page will list the enabled key bindings and provide a way for users to add and remove them.
|
||||
|
||||

|
||||
|
||||
When someone hovers over one of the items in the table, the Edit and Delete buttons will appear. Below is what the modal looks like if they were to click Edit on a command that does not have any arguments/actions. In the future, we would want this text box to be able to listen for key combinations. This would add a "listen" button to the UI.
|
||||
|
||||

|
||||
|
||||
If the command they select has additional arguments/actions, the modal will dynamically size as arguments/actions are added.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Settings layout
|
||||
|
||||
Below is the list of all settings on their respective pages in the settings UI. The title row aligns with the navigation view on the left of the UI. Bolded headers in those columns align with top nav on the page.
|
||||
|
||||
| General - Startup | General - Interaction | General - Rendering | Appearance - Global | Appearance - Color Schemes | Profiles - Global | Profiles - Enumerate profiles | Profiles - Add new |
|
||||
| ---------------- | --------------------- | ------------------- | ------------------- | -------------------------- | ----------------- | ----------------------------- | ------------------ |
|
||||
| Default profile (dropdown) | Copy after selection is made (checkbox) | Software rendering (checkbox) | Theme (radio) | Name (text box) | **General** | **General** | **General** | **General** |
|
||||
| Launch on startup (checkbox) | Copy formatting (checkbox) | Screen redrawing (checkbox) | Show/Hide the title bar (checkbox) | Cursor color (color picker) | Command line (text box) | Scrollbar visibility (radio) | Scrollbar visibility (radio) |
|
||||
| Launch size (radio) | Word delimiters (text box) | | Show terminal title in title bar (checkbox) | Selection background (color picker) | Starting directory (browse button) | Command line (browse button) | Command line (browse button) |
|
||||
| Launch position (text box) | Window resize behavior (checkbox) | | Always show tabs (checkbox) | Background (color picker) | Icon (browse button) | Starting directory (browse button) | Starting directory (browse button) |
|
||||
| Columns on first launch (number picker) | | | Tab width mode (radio) | Foreground (color picker) | Tab title (text box) | Name (text box) | Name (text box) |
|
||||
| Rows on first launch (number picker) | | | Hide close all tabs popup (checkbox) | Black (color picker) | Scrollbar visibility (radio) | Icon (browse button) | Icon (browse button) |
|
||||
| Automatically create new profiles when new shells are installed (checkbox) | | | | Blue (color picker) | **Appearance** | Tab title (text box) | Tab title (text box) |
|
||||
| | | | | Cyan (color picker) | Font face (text box) | **Appearance** | **Appearance** |
|
||||
| | | | | Green (color picker) | Font size (number picker) | Retro terminal effects (checkbox) | Retro terminal effects (checkbox) |
|
||||
| | | | | Purple (color picker) | Font weight (dropdown) | Font face (text box) | Font face (text box) |
|
||||
| | | | | Red (color picker) | Padding (text box) | Font size (number picker) | Font size (number picker) |
|
||||
| | | | | White (color picker) | Cursor shape (radio) | Font weight (dropdown) | Font weight (dropdown) |
|
||||
| | | | | Yellow (color picker) | Cursor color (color picker) | Padding (text box) | Padding (text box) |
|
||||
| | | | | Bright black (color picker) | Cursor height (number picker) | Cursor shape (radio) | Cursor shape (radio) |
|
||||
| | | | | Bright blue (color picker) | Color scheme (dropdown) | Cursor color (color picker) | Cursor color (color picker) |
|
||||
| | | | | Bright cyan (color picker) | Foreground color (color picker) | Cursor height (number picker) | Cursor height (number picker) |
|
||||
| | | | | Bright green (color picker) | Background color (color picker) | Color scheme (dropdown) | Color scheme (dropdown) |
|
||||
| | | | | Bright purple (color picker) | Selection background color (color picker) | Foreground color (color picker) | Foreground color (color picker) |
|
||||
| | | | | Bright red (color picker) | Enable acrylic (checkbox) | Background color (color picker) | Background color (color picker) |
|
||||
| | | | | Bright white (color picker) | Acrylic opacity (number picker) | Selection background color (color picker) | Selection background color (color picker) |
|
||||
| | | | | Bright yellow (color picker) | Background image (browse button) | Enable acrylic (checkbox) | Enable acrylic (checkbox) |
|
||||
| | | | | | Background image stretch mode (radio) | Acrylic opacity (number picker) | Acrylic opacity (number picker) |
|
||||
| | | | | | Background image alignment (dropdown) | Background image (browse button) | Background image (browse button) |
|
||||
| | | | | | Background image opacity (number picker) | Background image stretch mode (radio) | Background image stretch mode (radio) |
|
||||
| | | | | | Retro terminal effects (checkbox) | Background image alignment (dropdown) | Background image alignment (dropdown) |
|
||||
| | | | | | **Advanced** | Background image opacity (number picker) | Background image opacity (number picker) |
|
||||
| | | | | | Hide profile from dropdown (checkbox) | **Advanced** | **Advanced** |
|
||||
| | | | | | Suppress title changes (checkbox) | GUID (text box) | GUID (text box) |
|
||||
| | | | | | Antialiasing text (radio) | Hide profile from dropdown (checkbox) | Hide profile from dropdown (checkbox) |
|
||||
| | | | | | AltGr aliasing (checkbox) | Suppress title changes (checkbox) | Suppress title changes (checkbox) |
|
||||
| | | | | | Scroll to input when typing (checkbox) | Antialiasing text (radio) | Antialiasing text (radio) |
|
||||
| | | | | | History size (number picker) | AltGr aliasing (checkbox) | AltGr aliasing (checkbox) |
|
||||
| | | | | | How the profile closes (radio) | Scroll to input when typing (checkbox) | Scroll to input when typing (checkbox) |
|
||||
| | | | | | | History size (number picker) | History size (number picker) |
|
||||
| | | | | | | How the profile closes (radio) | How the profile closes (radio) |
|
||||
|
||||
## Potential Issues
|
||||
|
||||
## Future considerations
|
||||
|
||||
## Resources
|
||||
BIN
doc/specs/#1564 - Settings UI/keyboard-modal-add.png
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
doc/specs/#1564 - Settings UI/keyboard-modal-args.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
doc/specs/#1564 - Settings UI/keyboard-modal.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
doc/specs/#1564 - Settings UI/keyboard.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
doc/specs/#1564 - Settings UI/navigation-2.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
doc/specs/#1564 - Settings UI/navigation.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
122
doc/specs/#1564 - Settings UI/spec.md
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
author: Kayla Cinnamon @cinnamon-msft
|
||||
created on: 2020-06-29
|
||||
last updated: 2020-08-10
|
||||
issue id: #1564
|
||||
---
|
||||
|
||||
# Settings UI Implementation
|
||||
|
||||
## Abstract
|
||||
|
||||
This spec describes the basic functionality of the settings UI, including disabling it, the navigation items, launch methods, and editing of settings. The specific layout of each page will defined in later design reviews.
|
||||
|
||||
## Inspiration
|
||||
|
||||
We have been wanting a settings UI since the dawn of Terminal time, so we need to define how it will interact with the application and how users should expect to interact with it.
|
||||
|
||||
## Solution Design
|
||||
|
||||
The settings UI will be the default experience. We will provide users an option to skip the settings UI and edit the raw JSON file.
|
||||
|
||||
### Ability to disable displaying the settings UI
|
||||
|
||||
Some users don't want a UI for the settings. We can update the `openSettings` key binding with a `settingsUI` option.
|
||||
|
||||
If people still like the UI but want to access the JSON file, we can provide an "Open the JSON file" button at the bottom of the navigation menu.
|
||||
|
||||
### Launch method: launch in a new tab
|
||||
|
||||
Clicking the settings button in the dropdown menu will open the settings UI in a new tab. This helps us take steps toward supporting non-terminal content in a tab. Users will be able to see their visual changes by using the preview window inside the settings UI on relevant pages.
|
||||
|
||||
#### We also considered: launch in a new window
|
||||
|
||||
Clicking the settings button in the dropdown menu will open the settings UI in a new window. This allows the user to edit their settings and see the Terminal live update with their changes.
|
||||
|
||||
In the Windows taskbar, the icon will appear as if Terminal has multiple windows open.
|
||||
|
||||
### Editing and saving settings: implement a save button
|
||||
|
||||
Users will only see their settings changes take place once they click "Save". Clicking "Save" will write to the settings.json file. This aligns with the functionality that exists today by editing the settings.json file in a text editor and saving it.
|
||||
|
||||
We will also be adding a TerminalControl inside the settings UI to preview what the changes will look like before actually saving them to the settings.json file.
|
||||
|
||||
#### We also considered: automatically save settings
|
||||
|
||||
As users edit fields in the settings UI, they are automatically saved and written to the JSON file. This allows the user to see their settings changes taking place in real time.
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
Layout of all of the settings per page can be found in the [design doc](./design.md).
|
||||
|
||||
### Top-level navigation: more descriptive navigation
|
||||
|
||||
The navigation menu is broken up into more digestible sections. This aligns more closely to other terminals. The following are the proposed navigation items:
|
||||
|
||||
- General
|
||||
- Startup
|
||||
- Interaction
|
||||
- Rendering
|
||||
- Appearance
|
||||
- Global
|
||||
- Color schemes
|
||||
- Themes*
|
||||
- Profiles
|
||||
- Defaults
|
||||
- Enumerate profiles
|
||||
- Add new
|
||||
- Keyboard
|
||||
- Mouse*
|
||||
- Command Palette*
|
||||
- Marketplace*
|
||||
|
||||
\* Themes, mouse, command palette, and marketplace will be added once they're implemented.
|
||||
|
||||

|
||||
|
||||
#### We also considered: align with JSON
|
||||
|
||||
The settings UI could have top-level navigation that aligns with the overall structure of the settings.json file. The following are the proposed navigation items:
|
||||
|
||||
- Globals
|
||||
- Profiles
|
||||
- Color schemes
|
||||
- Bindings
|
||||
|
||||
For Bindings, it would have key bindings, mouse bindings, and command palette inside it.
|
||||
|
||||

|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
This will have to undergo full accessibility testing because it is a new UI element. All items inside the settings UI should be accessible by a screen reader and the keyboard. Additionally, all of the settings UI will have to be localized.
|
||||
|
||||
### Security
|
||||
|
||||
This does not impact security.
|
||||
|
||||
### Reliability
|
||||
|
||||
This will not improve reliability.
|
||||
|
||||
### Compatibility
|
||||
|
||||
This will change the default experience to open the UI, rather than the JSON file in a text editor. This behavior can be reverted with the setting listed [above](#ability-to-disable-displaying-the-settings-ui).
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
This does not affect performance, power, nor efficiency.
|
||||
|
||||
## Potential Issues
|
||||
|
||||
## Future considerations
|
||||
|
||||
- We will have to have design reviews for all of the content pages.
|
||||
- The `hidden` property will need special consideration. Ideally, all profiles will appear in the settings regardless if `hidden` is set to `true`.
|
||||
- We should have undo functionality. In a text editor, you can type `Ctrl+Z` however the settings UI is a bit more complex.
|
||||
- Once we have a marketplace for themes and extensions, this should be added to the top-level navigation.
|
||||
- As we add more features, the top-level navigation is subject to change in favor of improved usability.
|
||||
|
||||
## Resources
|
||||
@@ -0,0 +1,300 @@
|
||||
---
|
||||
author: Mike Griese @zadjii-msft
|
||||
created on: 2020-5-13
|
||||
last updated: 2020-08-04
|
||||
issue id: 1571
|
||||
---
|
||||
|
||||
# New Tab Menu Customization
|
||||
|
||||
## Abstract
|
||||
|
||||
Many users have lots and _lots_ of profiles that they use. Some of these
|
||||
profiles the user might not use that frequently. When that happens, the new tab
|
||||
dropdown can become quite cluttered.
|
||||
|
||||
A common ask is for the ability to reorder and reorganize this dropdown. This
|
||||
spec provides a design for how the user might be able to specify the
|
||||
customization in their settings.
|
||||
|
||||
## Inspiration
|
||||
|
||||
Largely, this spec was inspired by discussion in
|
||||
[#1571](https://github.com/microsoft/terminal/issues/1571#issuecomment-519504048)
|
||||
and the _many_ linked threads.
|
||||
|
||||
## Solution Design
|
||||
|
||||
This design proposes adding a new setting `"newTabMenu"`. When unset, (the
|
||||
default), the new tab menu is populated with all the profiles, in the order they
|
||||
appear in the users settings file. When set, this enables the user to control
|
||||
the appearance of the new tab dropdown. Let's take a look at an example:
|
||||
|
||||
```json
|
||||
{
|
||||
"profiles":{ ... },
|
||||
"newTabMenu": [
|
||||
{ "type":"profile", "profile": "cmd" },
|
||||
{ "type":"profile", "profile": "Windows PowerShell" },
|
||||
{ "type":"separator" },
|
||||
{
|
||||
"type":"folder",
|
||||
"name": "ssh",
|
||||
"icon": "C:\\path\\to\\icon.png",
|
||||
"entries":[
|
||||
{ "type":"profile", "profile": "Host 1" },
|
||||
{ "type":"profile", "profile": "8.8.8.8" },
|
||||
{ "type":"profile", "profile": "Host 2" }
|
||||
]
|
||||
},
|
||||
{ "type":"separator" },
|
||||
{ "type":"profile", "profile": "Ubuntu-18.04" },
|
||||
{ "type":"profile", "profile": "Fedora" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If a user were to use this as their new tab menu, that they would get is a menu
|
||||
that looks like this:
|
||||
|
||||

|
||||
|
||||
_fig 1_: A _very rough_ mockup of what this feature might look like
|
||||
|
||||
There are five `type`s of objects in this menu:
|
||||
* `"type":"profile"`: This is a profile. Clicking on this entry will open a new
|
||||
tab, with that profile. The profile is identified with the `"profile"`
|
||||
parameter, which accepts either a profile `name` or GUID. The icon for this
|
||||
entry will be the profile's icon, and the text on the entry will be the
|
||||
profile's name.
|
||||
* `"type":"separator"`: This represents a XAML `MenuFlyoutSeparator`, enabling
|
||||
the user to visually space out entries.
|
||||
* `"type":"folder"`: This represents a nested menu of entries.
|
||||
- The `"name"` property provides a string of text to display for the group.
|
||||
- The `"icon"` property provides a path to a image to use as the icon. This
|
||||
property is optional.
|
||||
- The `"entries"` property specifies a list of menu entries that will appear
|
||||
nested under this entry. This can contain other `"type":"folder"` groups as
|
||||
well!
|
||||
* `"type":"action"`: This represents a menu entry that should execute a specific
|
||||
`ShortcutAction`.
|
||||
- the `id` property will specify the global action ID (see [#6899], [#7175])
|
||||
to identify the action to perform when the user selects the entry. Actions
|
||||
with invalid IDs will be ignored and omitted from the list.
|
||||
- The text for this entry will be the action's label (which is
|
||||
either provided as the `"name"` in the global list of actions, or the
|
||||
generated name if no `name` was provided)
|
||||
- The icon for this entry will similarly re-use the action's `icon`.
|
||||
* `"type":"remainingProfiles"`: This is a special type of entry that will be
|
||||
expanded to contain one `"type":"profile"` entry for every profile that was
|
||||
not already listed in the menu. This will allow users to add one entry for
|
||||
just "all the profiles they haven't manually added to the menu".
|
||||
- This type of entry can only be specified once - trying to add it to the menu
|
||||
twice will raise a warning, and ignore all but the first `remainingProfiles`
|
||||
entry.
|
||||
- This type of entry can also be set inside a `folder` entry, allowing users
|
||||
to highlight only a couple profiles in the top-level of the menu, but
|
||||
enabling all other profiles to also be accessible.
|
||||
- The "name" of these entries will simply be the name of the profile
|
||||
- The "icon" of these entries will simply be the profile's icon
|
||||
|
||||
The "default" new tab menu could be imagined as the following blob of json:
|
||||
|
||||
```json
|
||||
{
|
||||
"newTabMenu": [
|
||||
{ "type":"remainingProfiles" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Other considerations
|
||||
|
||||
Also considered during the investigation for this feature was re-using the list
|
||||
of profiles to expose the structure of the new tab menu. For example, doing
|
||||
something like:
|
||||
|
||||
```json
|
||||
"profiles": {
|
||||
"defaults": {},
|
||||
"list":
|
||||
[
|
||||
{ "name": "cmd" },
|
||||
{ "name": "powershell" },
|
||||
{ "type": "separator" },
|
||||
{
|
||||
"type": "folder" ,
|
||||
"profiles": [
|
||||
{ "name": "ubuntu" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This option was not pursued because we felt that it needlessly complicated the
|
||||
contents of the list of profiles objects. We'd rather have the `profiles` list
|
||||
exclusively contain `Profile` objects, and have other elements of the json
|
||||
_refer_ to those profiles. What if someone would like to have an action that
|
||||
opened a new tab with profile index 4, and then they set that action as entry 4
|
||||
in the profile's list? That would certainly be some sort of unexpected behavior.
|
||||
|
||||
Additionally, what if someone wants to have an entry that opens a tab with one
|
||||
pane with one profile in it, and another pane with different profile in it? Or
|
||||
what if they want the same profile to appear twice in the menu?
|
||||
|
||||
By overloading the structure of the `profiles` list, we're forcing all other
|
||||
consumers of the list of profiles to care about the structure of the elements of
|
||||
the list. These other consumers should only really care about the list of
|
||||
profiles, and not necessarily how they're structured in the new tab dropdown.
|
||||
Furthermore, it complicates the list of profiles, by adding actions intermixed
|
||||
with the profiles.
|
||||
|
||||
The design chosen in this spec more cleanly separates the responsibilities of
|
||||
the list of profiles and the contents of the new tab menu. This way, each object
|
||||
can be defined independent of the structure of the other.
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
See the above _figure 1_.
|
||||
|
||||
The profile's `icon` will also appear as the icon on `profile` entries. If
|
||||
there's a keybinding bound to open a new tab with that profile, then that will
|
||||
also be added to the `MenuFlyoutItem` as the accelerator text, similar to the
|
||||
text we have nowadays.
|
||||
|
||||
Beneath the list of profiles will _always_ be the same "Settings", "Feedback"
|
||||
and "About" entries, separated by a `MenuFlyoutSeparator`. This is consistent
|
||||
with the UI as it exists with no customization. These entries cannot be removed
|
||||
with this feature, only the list of profiles customized.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
This menu will be added to the XAML tree in the same fashion as the current new
|
||||
tab flyout, so there should be no dramatic change here.
|
||||
|
||||
### Security
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
### Reliability
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
### Compatibility
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
## Potential Issues
|
||||
|
||||
Currently, the `openTab` and `splitPane` keybindings will accept a `index`
|
||||
parameter to say either:
|
||||
* "Create a new tab/pane with the N'th profile"
|
||||
* "Create a new tab/pane with the profile at index N in the new
|
||||
tab dropdown".
|
||||
|
||||
These two were previously synonymous, as the N'th profile was always the N'th in
|
||||
the dropdown. However, with this change, we'll be changing the meaning of that
|
||||
argument to mean explicitly the first option - "Open a tab/pane with the N'th
|
||||
profile".
|
||||
|
||||
A previous version of this spec considered changing the meaning of that
|
||||
parameter to mean "open the entry at index N", the second option. However, in
|
||||
[Command Palette, Addendum 1], we found that naming that command would become
|
||||
unnecessarily complex.
|
||||
|
||||
To cover that above scenario, we could consider adding an `index` parameter to
|
||||
the `openNewTabDropdown` action. If specified, that would open either the N'th
|
||||
action in the dropdown (ignoring separators), or open the dropdown with the n'th
|
||||
item selected.
|
||||
|
||||
The N'th entry in the menu won't always be a profile: it might be a folder with
|
||||
more options, or it might be an action (that might not be opening a new tab/pane
|
||||
at all).
|
||||
|
||||
Given all the above scenarios, `openNewTabDropdown` with an `"index":N`
|
||||
parameter will behave in the following ways. If the Nth top-level entry in the
|
||||
new tab menu is a:
|
||||
* `"type":"profile"`: perform the `newTab` or `splitPane` action with that profile.
|
||||
* `"type":"folder"`: Focus the first element in the sub menu, so the user could
|
||||
navigate it with the keyboard.
|
||||
* `"type":"separator"`: Ignore these when counting top-level entries.
|
||||
* `"type":"action"`: Perform the action.
|
||||
|
||||
So for example:
|
||||
|
||||
```
|
||||
New Tab Button ▽
|
||||
├─ Folder 1
|
||||
│ └─ Profile A
|
||||
│ └─ Action B
|
||||
├─ Separator
|
||||
├─ Folder 2
|
||||
│ └─ Profile C
|
||||
│ └─ Profile D
|
||||
├─ Action E
|
||||
└─ Profile F
|
||||
```
|
||||
|
||||
And assuming the user has bound:
|
||||
```json
|
||||
{
|
||||
"bindings":
|
||||
[
|
||||
{ "command": { "action": "openNewTabDropdown", "index": 0 }, "keys": "ctrl+shift+1" },
|
||||
{ "command": { "action": "openNewTabDropdown", "index": 1 }, "keys": "ctrl+shift+2" },
|
||||
{ "command": { "action": "openNewTabDropdown", "index": 2 }, "keys": "ctrl+shift+3" },
|
||||
{ "command": { "action": "openNewTabDropdown", "index": 3 }, "keys": "ctrl+shift+4" },
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
* <kbd>ctrl+shift+1</kbd> focuses "Profile A", but the user needs to press
|
||||
enter/space to creates a new tab/split
|
||||
* <kbd>ctrl+shift+2</kbd> focuses "Profile C", but the user needs to press
|
||||
enter/space to creates a new tab/split
|
||||
* <kbd>ctrl+shift+3</kbd> performs Action E
|
||||
* <kbd>ctrl+shift+4</kbd> Creates a new tab/split with Profile F
|
||||
|
||||
## Future considerations
|
||||
|
||||
* The user could set a `"name"`/`"text"`, or `"icon"` property to these menu
|
||||
items manually, to override the value from the profile or action. These
|
||||
settings would be totally optional, but it's not unreasonable that someone
|
||||
might want this.
|
||||
* We may want to consider adding a default icon for all folders or actions in
|
||||
the menu. For example, a folder (like 📁) for `folder` entries, or something
|
||||
like ⚡ for actions. We'll leave these unset by default, and evaluate setting
|
||||
these icons by default in the future.
|
||||
* Something considered during review was a way to specify "All my WSL profiles".
|
||||
Maybe the user wants to have all their profiles generated by the WSL Distro
|
||||
Generator appear in a "WSL" folder. This would likely require a more elaborate
|
||||
filtering syntax, to be able to select only profiles where a certain property
|
||||
has a specific value. Consider the user who has multiple "SSH
|
||||
me@\<some host\>.com" profiles, and they want all their "SSH\*" profiles to
|
||||
appear in an "SSH" folder. This feels out-of-scope for this spec.
|
||||
* A similar structure could potentially also be used for customizing the context
|
||||
menu within a control, or the context menu for the tab. (see [#3337])
|
||||
- In both of those cases, it might be important to somehow refer to the
|
||||
context of the current tab or control in the json. Think for example about
|
||||
"Close tab" or "Close other tabs" - currently, those work by _knowing_ which
|
||||
tab the "action" is specified for, not by actually using a `closeTab` action.
|
||||
In the future, they might need to be implemented as something like
|
||||
- Close Tab: `{ "action": "closeTab", "index": "${selectedTab.index}" }`
|
||||
- Close Other Tabs: `{ "action": "closeTabs", "otherThan": "${selectedTab.index}" }`
|
||||
- Close Tabs to the Right: `{ "action": "closeTabs", "after": "${selectedTab.index}" }`
|
||||
|
||||
|
||||
<!-- Footnotes -->
|
||||
[#2046]: https://github.com/microsoft/terminal/issues/2046
|
||||
[Command Palette, Addendum 1]: https://github.com/microsoft/terminal/blob/main/doc/specs/%232046%20-%20Unified%20keybindings%20and%20commands%2C%20and%20synthesized%20action%20names.md
|
||||
|
||||
[#3337]: https://github.com/microsoft/terminal/issues/3337
|
||||
[#6899]: https://github.com/microsoft/terminal/issues/6899
|
||||
[#7175]: https://github.com/microsoft/terminal/issues/7175
|
||||
|
After Width: | Height: | Size: 46 KiB |
@@ -605,4 +605,4 @@ as well as 3 schemes: "Scheme 1", "Scheme 2", and "Scheme 3".
|
||||
|
||||
|
||||
<!-- Footnotes -->
|
||||
[Command Palette Spec]: https://github.com/microsoft/terminal/blob/master/doc/specs/%232046%20-%20Command%20Palette.md
|
||||
[Command Palette Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%232046%20-%20Command%20Palette.md
|
||||
|
||||
228
doc/specs/#6899 - Action IDs/#6899 - Action IDs.md
Normal file
@@ -0,0 +1,228 @@
|
||||
---
|
||||
author: Mike Griese @zadjii-msft
|
||||
created on: 2020-07-13
|
||||
last updated: 2020-07-22
|
||||
issue id: 6899
|
||||
---
|
||||
|
||||
# Action IDs
|
||||
|
||||
## Abstract
|
||||
|
||||
This document is intended to serve as an addition to the [Command Palette Spec],
|
||||
as well as the [New Tab Menu Customization Spec].
|
||||
|
||||
As we come to rely more on actions being a mechanism by which the user defines
|
||||
"do something in the Terminal", we'll want to make it even easier for users to
|
||||
re-use the actions that they've already defined, as to reduce duplicated json as
|
||||
much as possible. This spec proposes a mechanism by which actions could be
|
||||
uniquely identifiable, so that the user could refer to bindings in other
|
||||
contexts without needing to replicate an entire json blob.
|
||||
|
||||
## Solution Design
|
||||
|
||||
This spec was largely inspired by the following diagram from @DHowett:
|
||||
|
||||

|
||||
|
||||
The goal is to introduce an `id` parameter by which actions could be uniquely
|
||||
refered to. If we'd ever like to use an action outside the list of `actions`, we
|
||||
can simply refer to the action's ID, allowing the user to only define the action
|
||||
_once_.
|
||||
|
||||
We'll start by renaming `bindings` to `actions`. `bindings` was suggested as a
|
||||
rename for `keybindings` in [#6532], as a way to make the name more generic.
|
||||
Discussion with the team lead to the understanding that the name `actions` would
|
||||
be even better, as a way of making the meaning of the "list of actions" more
|
||||
obvious.
|
||||
|
||||
When we're parsing `actions`, we'll make three passes:
|
||||
* The first pass will scan the list for objects with an `id` property. We'll
|
||||
attempt to parse those entries into `ActionAndArgs` which we'll store in the
|
||||
global `id->ActionAndArgs` map. If any entry doesn't have an `id` set, we'll
|
||||
skip it in this phase. If an entry doesn't have a `command` set, we'll ignore
|
||||
it in this pass.
|
||||
* The second pass will scan for _keybindings_. Any entries with `keys` set will
|
||||
create a `KeyChord->ActionAndArgs` entry in the keybindings map. If the entry
|
||||
has an `id` set, then we'll simply re-use the action we've already parsed for
|
||||
the `id`, from the action map. If there isn't an `id`, then we'll parse the
|
||||
action manually at this time. Entries without a `keys` set will be ignored in
|
||||
this pass.
|
||||
* The final pass will be to generate _commands_. Similar to the keybindings
|
||||
pass, we'll attempt to lookup actions for entries with an `id` set. If there
|
||||
isn't an `id`, then we'll parse the action manually at this time. We'll then
|
||||
get the name for the entry, either from the `name` property if it's set, or
|
||||
the action's `GenerateName` method.
|
||||
|
||||
For a visual representation, let's assume the user has the following in their
|
||||
`actions`:
|
||||
|
||||

|
||||
|
||||
We'll first parse the `actions` to generate the mapping of `id`->`Actions`:
|
||||
|
||||

|
||||
|
||||
Then, we'll parse the `actions` to generate the mapping of keys to actions, with
|
||||
some actions already being defined in the map of `id`->`Actions`:
|
||||
|
||||

|
||||
|
||||
|
||||
When layering `actions`, if a later settings file contains an action with the
|
||||
same `id`, it will replace the current value. In this way, users can redefine
|
||||
actions, or remove default ones (with something like `{ "id":
|
||||
"Terminal.OpenTab", "command":null }`
|
||||
|
||||
We'd maintain a large list of default actions, each with unique `id`s set. These
|
||||
are all given `id`'s with a `Terminal.` prefix, to easily identify them as
|
||||
built-in, default actions. Not all of these actions will be given keys, but they
|
||||
will all be given `id`s.
|
||||
|
||||
> 👉 NOTE: The IDs for the default actions will need to be manually created, not
|
||||
> autogenerated. These `id`s are not strings displayed in the user interface, so
|
||||
> localization is not a concern.
|
||||
|
||||
As we add additional menus to the Terminal, like the customization for the new
|
||||
tab dropdown, or the tab context menu, or the `TermControl` context menu, they
|
||||
could all refer to these actions by `id`, rather than duplicating the same json.
|
||||
|
||||
|
||||
### Existing Scenarios
|
||||
|
||||
Keybindings will still be stored as a `keys->Action` mapping, so the user will
|
||||
still be able to override default keybindings exactly the same as before.
|
||||
|
||||
Similarly, commands in the Command Palette will continue using their existing
|
||||
`name->Action` mapping they're currently using. For a binding like
|
||||
|
||||
```json
|
||||
{ "keys": "ctrl+alt+x", "id": "Terminal.OpenDefaultSettings" },
|
||||
```
|
||||
* We'll bind whatever action is defined as `Terminal.OpenDefaultSettings` to
|
||||
<kbd>ctrl+alt+x</kbd>.
|
||||
* We'll use whatever action is defined as `Terminal.OpenDefaultSettings` to
|
||||
generate a name for the command palette.
|
||||
|
||||
### Future Context Menus
|
||||
|
||||
In [New Tab Menu Customization Spec], we discuss allowing the user to bind
|
||||
actions to the new tab menu. In that spec, they can do so with something like
|
||||
the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"newTabMenu": [
|
||||
{ "type":"action", "command": { "action": "adjustFontSize", "delta": 1 }, }
|
||||
{ "type":"action", "command": { "action": "adjustFontSize", "delta": -1 }, }
|
||||
{ "type":"action", "command": "resetFontSize", }
|
||||
{ "type":"profile", "profile": "cmd" },
|
||||
{ "type":"profile", "profile": "Windows PowerShell" },
|
||||
{ "type":"separator" },
|
||||
{
|
||||
"type":"folder",
|
||||
"name": "Settings...",
|
||||
"icon": "C:\\path\\to\\icon.png",
|
||||
"entries":[
|
||||
{ "type":"action", "command": "openSettings" },
|
||||
{ "type":"action", "command": { "action": "openSettings", "target": "defaultsFile" } },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the user has also exposed the "Increase font size", "Decrease
|
||||
font size", and "Reset font size" actions, as well as the settings files in a
|
||||
submenu. With this proposal, the above could instead be re-written as:
|
||||
|
||||
```json
|
||||
{
|
||||
"newTabMenu": [
|
||||
{ "type":"action", "id": "Terminal.IncreaseFontSize" },
|
||||
{ "type":"action", "id": "Terminal.DecreaseFontSize" },
|
||||
{ "type":"action", "id": "Terminal.ResetFontSize" },
|
||||
{ "type":"profile", "profile": "cmd" },
|
||||
{ "type":"profile", "profile": "Windows PowerShell" },
|
||||
{ "type":"separator" },
|
||||
{
|
||||
"type":"folder",
|
||||
"name": "Settings...",
|
||||
"icon": "C:\\path\\to\\icon.png",
|
||||
"entries":[
|
||||
{ "type":"action", "id": "Terminal.OpenDefaultSettings" },
|
||||
{ "type":"action", "id": "Terminal.OpenSettings" },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the actions are looked up from the global map using the `id`
|
||||
provided, enabling the user to re-use their existing definitions. If the user
|
||||
re-defined the `Terminal.IncreaseFontSize` action to mean something else, then
|
||||
the action in the new tab menu will also be automatically updated.
|
||||
|
||||
Furthermore, when additional menus are added (such as the tab context menu, or
|
||||
the `TermControl` context menu), these could also leverage a similar syntax to
|
||||
the above to allow re-use of the `id` parameter.
|
||||
|
||||
Discussion with the team also suggested that users shouldn't be able to define
|
||||
actions in these menus _at all_. The actions should exclusively be defined in
|
||||
`actions`, and other menus should only be able to refer to these actions by
|
||||
`id`.
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
There's not a whole lot of UI for this feature specifically. This is largely
|
||||
behind-the-scenes refactoring of how actions can be defined.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
_(not applicable)_
|
||||
|
||||
### Security
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
### Reliability
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
### Compatibility
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
_(no change expected)_
|
||||
|
||||
## Potential Issues
|
||||
|
||||
This won't necessarily play well with iterable commands in the Command Palette,
|
||||
but that's okay. For iterable commands, users will still need to define the
|
||||
actions manually.
|
||||
|
||||
## Future considerations
|
||||
|
||||
* See the following issues for other places where this might be useful:
|
||||
- [#1912] - Context Menu for Tabs
|
||||
* See also [#5524], [#5025], [#5633]
|
||||
- [#3337] - Right-click menu inside TerminalControl (w/ Copy & Paste?)
|
||||
* See also [#5633] and [#5025], both those actions seem reasonable in either
|
||||
the tab context menu or the control context menu.
|
||||
|
||||
<!-- Footnotes -->
|
||||
[Command Palette Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%232046%20-%20Command%20Palette.md
|
||||
[New Tab Menu Customization Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%231571%20-%20New%20Tab%20Menu%20Customization.md
|
||||
|
||||
[#1571]: https://github.com/microsoft/terminal/issues/1571
|
||||
[#1912]: https://github.com/microsoft/terminal/issues/1912
|
||||
[#3337]: https://github.com/microsoft/terminal/issues/3337
|
||||
[#5025]: https://github.com/microsoft/terminal/issues/5025
|
||||
[#5524]: https://github.com/microsoft/terminal/issues/5524
|
||||
[#5633]: https://github.com/microsoft/terminal/issues/5633
|
||||
[#6532]: https://github.com/microsoft/terminal/issues/6532
|
||||
[#6899]: https://github.com/microsoft/terminal/issues/6899
|
||||
BIN
doc/specs/#6899 - Action IDs/data-mockup-002.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 130 KiB |
BIN
doc/specs/#6899 - Action IDs/data-mockup-actions-and-ids.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
doc/specs/#6899 - Action IDs/data-mockup-actions.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
doc/specs/#6899 - Action IDs/data-mockup.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
@@ -0,0 +1,423 @@
|
||||
---
|
||||
author: Carlos Zamora @carlos-zamora
|
||||
created on: 2020-07-10
|
||||
last updated: 2020-07-10
|
||||
issue id: [#885](https://github.com/microsoft/terminal/issues/885)
|
||||
---
|
||||
|
||||
# Terminal Settings Model
|
||||
|
||||
## Abstract
|
||||
|
||||
This spec proposes a major refactor and repurposing of the TerminalSettings project as the TerminalSettingsModel.
|
||||
TerminalSettingsModel would be responsible for exposing, serializing, and deserializing settings as WinRT objects
|
||||
for Windows Terminal. In doing so, Terminal's settings model is accessible as WinRT objects to existing components
|
||||
like TerminalApp, TerminalControl, and TerminalCore. Additionally, Terminal Settings can be used by the Settings UI or
|
||||
Shell Extensions to modify or reference Terminal's settings respectively.
|
||||
|
||||
## Inspiration
|
||||
|
||||
The main driver for this change is the Settings UI. The Settings UI will need to read and modify Terminal's settings
|
||||
objects. At the time of writing this spec, the Terminal's settings are serialized as objects in the TerminalApp project.
|
||||
To access these objects via XAML, the Settings UI needs them to be WinRT objects. Additional features that need the
|
||||
settings objects to be WinRT objects include future shell extensions, like jumplist.
|
||||
|
||||
## Solution Design
|
||||
|
||||
### Terminal Settings Model: Objects and Projections
|
||||
|
||||
The following TerminalApp objects will become WinRT objects and will be moved to the TerminalSettingsModel project
|
||||
(formerly TerminalSettings):
|
||||
- ColorScheme
|
||||
- Profile
|
||||
- GlobalAppSettings
|
||||
- CascadiaSettings
|
||||
|
||||
The TerminalSettingsModel project will have a root namespace of `Microsoft.Terminal.Settings.Model`.
|
||||
|
||||
Adjacent to the introduction of these settings objects, `IControlSettings` and `ICoreSettings` will be moved
|
||||
to the `Microsoft.Terminal.TerminalControl` namespace. This allows for a better consumption of the
|
||||
settings model that is covered later in the (Consumption section)[#terminal-settings-model:-consumption].
|
||||
|
||||
#### Moving/Splitting the Action Model
|
||||
|
||||
Windows Terminal represents actions via several objects:
|
||||
- `AppKeyBindings`: a map of all the defined keybindings and their corresponding actions
|
||||
- `ActionAndArgs`: a (de)serializable action (this holds more objects inside of it, but we won't focus on that for now)
|
||||
- `ShortcutActionDispatch`: responsible for dispatching events pertinent to a given ActionAndArgs object
|
||||
`TerminalApp`'s `TerminalPage` handles any events dispatched by the `ShortcutActionDispatch`.
|
||||
|
||||
With the introduction of the TerminalSettingsModel, we will split `AppKeyBindings` using a `KeyMapping` class.
|
||||
This separation will look something like the following:
|
||||
```c++
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass AppKeyBindings : Microsoft.Terminal.TerminalControl.IKeyBindings
|
||||
{
|
||||
AppKeyBindings();
|
||||
|
||||
// NOTE: It may be possible to move both of these to the constructor instead
|
||||
void SetDispatch(ShortcutActionDispatch dispatch);
|
||||
void SetKeyMap(KeyMapping keymap);
|
||||
}
|
||||
}
|
||||
|
||||
namespace TerminalSettingsModel
|
||||
{
|
||||
[default_interface] runtimeclass KeyMapping
|
||||
{
|
||||
void SetKeyBinding(ActionAndArgs actionAndArgs, Microsoft.Terminal.TerminalControl.KeyChord chord);
|
||||
void ClearKeyBinding(Microsoft.Terminal.TerminalControl.KeyChord chord);
|
||||
|
||||
Microsoft.Terminal.TerminalControl.KeyChord GetKeyBindingForAction(ShortcutAction action);
|
||||
Microsoft.Terminal.TerminalControl.KeyChord GetKeyBindingForActionWithArgs(ActionAndArgs actionAndArgs);
|
||||
}
|
||||
}
|
||||
```
|
||||
This separation leaves `AppKeyBindings` with the responsibility of detecting and dispatching actions, whereas
|
||||
`KeyMapping` handles the (de)serialization and navigation of the key bindings.
|
||||
|
||||
|
||||
### Fallback Value
|
||||
|
||||
Cascading settings allows our settings model to be constructed in layers (i.e. settings.json values override defaults.json values). With the upcoming introduction of the Settings UI and serialization, it is important to know where a setting value comes from. Consider a Settings UI displaying the following information:
|
||||
```json
|
||||
// <profile>: <color scheme value>
|
||||
"defaults": "Solarized", // profiles.defaults
|
||||
"A": "Raspberry", // profile A
|
||||
"B": "Tango", // profile B
|
||||
"C": "Solarized" // profile C
|
||||
```
|
||||
If `profiles.defaults` gets changed to `"Tango"` via the Settings UI, it is unclear if profile C's value should be updated as well. We need profile C to record if it's value is inherited from profile.defaults or explicitly set by the user.
|
||||
|
||||
#### Object Model Inheritance
|
||||
|
||||
To start, each settings object will now have a `CreateChild()` function. For `GlobalAppSettings`, it will look something like this:
|
||||
```c++
|
||||
GlobalAppSettings GlobalAppSettings::CreateChild() const
|
||||
{
|
||||
GlobalAppSettings child {};
|
||||
child._parents.append(this);
|
||||
return child;
|
||||
}
|
||||
```
|
||||
`std::vector<T> _parents` serves as a reference for who to ask if a settings value was not provided by the user. `LaunchMode`, for example, will now have a getter/setter that looks similar to this:
|
||||
```c++
|
||||
// _LaunchMode will now be a std::optional<LaunchMode> instead of a LaunchMode
|
||||
// - std::nullopt will mean that there is no user-set value
|
||||
// - otherwise, the value was explicitly set by the user
|
||||
|
||||
// returns the resolved value for this setting
|
||||
LaunchMode GlobalAppSettings::LaunchMode()
|
||||
{
|
||||
// fallback tree:
|
||||
// - user set value
|
||||
// - inherited value
|
||||
// - system set value
|
||||
return til::coalesce_value(_LaunchMode, _parents[0].LaunchMode(), _parents[1].LaunchMode(), ..., LaunchMode::DefaultMode);
|
||||
}
|
||||
|
||||
// explicitly set the user-set value
|
||||
void GlobalAppSettings::LaunchMode(LaunchMode val)
|
||||
{
|
||||
_LaunchMode = val;
|
||||
}
|
||||
|
||||
// check if there is a user-set value
|
||||
// NOTE: This is important for the Settings UI to identify whether the user explicitly or implicitly set the presented value
|
||||
bool GlobalAppSettings::HasLaunchMode()
|
||||
{
|
||||
return _LaunchMode.has_value();
|
||||
}
|
||||
|
||||
// explicitly unset the user-set value (we want the inherited value)
|
||||
void GlobalAppSettings::ClearLaunchMode()
|
||||
{
|
||||
return _LaunchMode = std::nullopt;
|
||||
}
|
||||
```
|
||||
|
||||
As a result, the tracking and functionality of cascading settings is moved into the object model instead of keeping it as a json-only concept.
|
||||
|
||||
#### Updates to CascadiaSettings
|
||||
|
||||
As `CascadiaSettings` loads the settings model, it will create children for each component of the settings model and layer the new values on top of it. Thus, `LayerJson` will look something like this:
|
||||
```c++
|
||||
void CascadiaSettings::LayerJson(const Json::Value& json)
|
||||
{
|
||||
_globals = _globals.CreateChild();
|
||||
_globals->LayerJson(json);
|
||||
|
||||
// repeat the same for Profiles...
|
||||
}
|
||||
```
|
||||
For `defaults.json`, `_globals` will now hold all of the values set in `defaults.json`. If any settings were omitted from the `defaults.json`, `_globals` will fallback to its parent (a `GlobalAppSettings` consisting purely of system-defined values).
|
||||
|
||||
For `settings.json`, `_globals` will only hold the values set in `settings.json`. If any settings were omitted from `settings.json`, `_globals` will fallback to its parent (the `GlobalAppSettings` built from `defaults.json`).
|
||||
|
||||
This process becomes a bit more complex for `Profile` because it can fallback in the following order:
|
||||
1. `settings.json` profile
|
||||
2. `settings.json` `profiles.defaults`
|
||||
3. (if a dynamic profile) the hardcoded value in the dynamic profile generator
|
||||
4. `defaults.json` profile
|
||||
|
||||
`CascadiaSettings` must do the following...
|
||||
1. load `defaults.json`
|
||||
- append newly created profiles to `_profiles` (unchanged)
|
||||
2. load dynamic profiles
|
||||
- append newly created profiles to `_profiles` (unchanged)
|
||||
3. load `settings.json` `profiles.defaults`
|
||||
- construct a `Profile` from `profiles.defaults`. Save as `Profile _profileDefaults`.
|
||||
- `CreateChild()` for each existing profile
|
||||
- add `_profileDefaults` as the first parent to each child (`_parents=[_profileDefaults, <value from generator/defaults.json> ]`)
|
||||
- replace each `Profile` in `_profiles` with the child
|
||||
4. load `settings.json` `profiles.list`
|
||||
- if a matching profile exists, `CreateChild` from the matching profile, and layer the json onto the child.
|
||||
- NOTE: we do _not_ include `_profileDefaults` as a parent here, because it is already an ancestor
|
||||
- otherwise, `CreateChild()` from `_profileDefaults`, and layer the json onto the child.
|
||||
- As before, `_profiles` must be updated such that the parent is removed
|
||||
|
||||
Additionally, `_profileDefaults` will be exposed by `Profile CascadiaSettings::ProfileDefaults()`. This will enable [#7414](https://github.com/microsoft/terminal/pull/7414)'s implementation to spawn incoming commandline app tabs with the "Default" profile (as opposed to the "default profile").
|
||||
|
||||
|
||||
#### Nullable Settings
|
||||
Some settings are explicitly allowed to be nullable (i.e. `Profile` `Foreground`). These settings will be stored as the following struct instead of a `std::optional<T>`:
|
||||
```c++
|
||||
template<typename T>
|
||||
struct NullableSetting
|
||||
{
|
||||
IReference<T> setting{ nullptr };
|
||||
bool set{ false };
|
||||
};
|
||||
```
|
||||
where...
|
||||
- `set` determines if the value was explicitly set by the user (if false, we should fall back)
|
||||
- `setting` records the actual user-set value (`nullptr` represents an explicit set to null)
|
||||
|
||||
The API surface will experience the following small changes:
|
||||
- the getter/setter will output/input an `IReference<T>` instead of `T`
|
||||
- `Has...()` and `Clear...()` will reference/modify `set`
|
||||
|
||||
|
||||
### CreateChild() vs Copy()
|
||||
|
||||
Settings objects will have `CreateChild()` and `Copy()`. `CreateChild()` is responsible for creating a new settings object that inherits undefined values from its parent. `Copy()` is responsible for recreating the contents of the settings object, including a reference to a copied parent (not the original parent).
|
||||
|
||||
`CreateChild()` will only be used during (de)serialization to adequately interpret and update the JSON. `CreateChild()` enables, but is not explicitly used, for retrieving a value from a settings object. It can also be used to enable larger hierarchies for inheritance within the settings model.
|
||||
|
||||
The Settings UI will use `Copy()` to get a deep copy of `CascadiaSettings` and data bind the UI to that copy. Thus, `Copy()` needs to be exposed in the IDL.
|
||||
|
||||
#### Copying _parents
|
||||
It is important that `_parents` is handled properly when performing a deep copy. We need to be aware of the following errors:
|
||||
- referencing `_parents` will result in inheriting from an obsolete object tree
|
||||
- referencing a copy of `_parents` can result in losing the meaning of a reference
|
||||
- For example, `profile.defaults` is a parent to each presented profile. When a change occurs to `profile.defaults`, that change should impact all profiles. An improper copy may only apply the change to one of the presented profiles
|
||||
|
||||
The hierarchy we have created has evolved into a directed acyclic graph (DAG). For example, the hierarchy for profiles will appear similar to the following:
|
||||
|
||||

|
||||
|
||||
In order to preserve `profile.defaults` as a referenced parent to each profile, a copy of the DAG can be performed using the following algorithm:
|
||||
```python
|
||||
# Function to clone a graph. To do this, we start
|
||||
# reading the original graph depth-wise, recursively
|
||||
# If we encounter an unvisited node in original graph,
|
||||
# we initialize a new instance of Node for
|
||||
# cloned graph with key of original node
|
||||
def cloneGraph(oldSource, newSource, visited):
|
||||
clone = None
|
||||
if visited[oldSource.key] is False and oldSource.adj is not None:
|
||||
for old in oldSource.adj:
|
||||
|
||||
# Below check is for backtracking, so new
|
||||
# nodes don't get initialized everytime
|
||||
if clone is None or(clone is not None and clone.key != old.key):
|
||||
clone = Node(old.key, [])
|
||||
newSource.adj.append(clone)
|
||||
cloneGraph(old, clone, visited)
|
||||
|
||||
# Once, all neighbors for that particular node
|
||||
# are created in cloned graph, code backtracks
|
||||
# and exits from that node, mark the node as
|
||||
# visited in original graph, and traverse the
|
||||
# next unvisited
|
||||
visited[old.key] = True
|
||||
return newSource
|
||||
```
|
||||
Source: https://www.geeksforgeeks.org/clone-directed-acyclic-graph/
|
||||
|
||||
This algorithm operates in O(n) time and space where `n` is the number of profiles presented. The above algorithm will be slightly modified to...
|
||||
- hold a separate reference to profile.defaults `Profile` in the `CascadiaSettings` clone
|
||||
- visited will be a map of pointers to the cloned `Profile`. This ensures that profiles reference the same `Profile`, over creating a new copy
|
||||
|
||||
### Terminal Settings Model: Serialization and Deserialization
|
||||
|
||||
Introducing these `Microsoft.Terminal.Settings.Model` WinRT objects also allow the serialization and deserialization
|
||||
logic from TerminalApp to be moved to TerminalSettings. `JsonUtils` introduces several quick and easy methods
|
||||
for setting deserialization. This will be moved into the `Microsoft.Terminal.Settings.Model` namespace too.
|
||||
|
||||
Serialization will be an extension of the existing `JsonUtils` `ConversionTrait` struct template. `ConversionTrait`
|
||||
already includes `FromJson` and `CanConvert`. Serialization would be handled by a `ToJson` function.
|
||||
|
||||
|
||||
### Terminal Settings Model: Warnings and Serialization Errors
|
||||
|
||||
Today, if the deserialization of `CascadiaSettings` encounters any errors, an exception is thrown and caught/handled
|
||||
by falling back to a simple `CascadiaSettings` object. However, WinRT does not support exceptions.
|
||||
|
||||
To get around this issue, when `CascadiaSettings` encounters a serialization error, it must internally record
|
||||
any pertinent information for that error, and return the simple `CascadiaSettings` as if nothing happened.
|
||||
The consumer must then call `CascadiaSettings::GetErrors()` and `CascadiaSettings::GetWarnings()` to properly
|
||||
understand whether an error ocurred and how to present that to the user.
|
||||
|
||||
|
||||
#### TerminalApp: Loading and Reloading Changes
|
||||
|
||||
TerminalApp will construct and reference a `CascadiaSettings settings` as follows:
|
||||
- TerminalApp will have a global reference to the "settings.json" filepath
|
||||
- construct an `CascadiaSettings` using `CascadiaSettings("settings.json")`. This builds an `CascadiaSettings`
|
||||
from the "defaults.json" file data (which is already compiled as a string literal)
|
||||
and layers the settings.json data on top of it.
|
||||
- check for errors/warnings, and handle them appropriately
|
||||
|
||||
This will be different from the current model which has the settings.json path hardcoded, and is simplified
|
||||
to a `LoadAll()` call wrapped in error handlers.
|
||||
|
||||
**NOTE:** This model allows us to layer even more settings files on top of the existing Terminal Settings
|
||||
Model, if so desired. This could be helpful when importing additional settings files from an external location
|
||||
such as a marketplace.
|
||||
|
||||
When TerminalApp detects a change to settings.json, it'll repeat the steps above. We could cache the result from
|
||||
constructing an `CascadiaSettings` from "defaults.json" data to improve performance.
|
||||
|
||||
|
||||
#### TerminalControl: Acquiring and Applying the Settings
|
||||
|
||||
At the time of writing this spec, TerminalApp constructs `TerminalControl.TerminalSettings` WinRT objects
|
||||
to expose `IControlSettings` and `ICoreSettings` to any hosted terminals. In moving `IControlSettings`
|
||||
and `ICoreSettings` down to the TerminalControl layer, TerminalApp can now have better control over
|
||||
how to expose relevant settings to a TerminalControl instance.
|
||||
|
||||
`TerminalSettings` (which implements `IControlSettings` and `ICoreSettings`) will be moved to
|
||||
TerminalApp and act as a bridge connecting `CascadiaSettings` to the TermControl. It will operate
|
||||
very similarly as it does today. On construction of the TermControl or hot-reload,
|
||||
`TerminalSettings` will be constructed by copying the relevant values of `CascadiaSettings`.
|
||||
Then, it will be passed to TermControl (and TermCore by extension).
|
||||
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
N/A
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
N/A
|
||||
|
||||
### Security
|
||||
|
||||
N/A
|
||||
|
||||
### Reliability
|
||||
|
||||
N/A
|
||||
|
||||
### Compatibility
|
||||
|
||||
N/A
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
## Potential Issues
|
||||
|
||||
N/A
|
||||
|
||||
## Future considerations
|
||||
|
||||
### TerminalSettings: passing by reference
|
||||
|
||||
`TermApp` synthesizes a `TerminalSettings` by copying the relevant values of `CascadiaSettings`,
|
||||
then giving it to a Terminal Control. Some visual keybindings and interactions like ctrl+scroll
|
||||
and ctrl+shift+scroll to change the font size and acrylic opacity operate by directly modifying
|
||||
the value of the instantiated `TerminalSettings`. However, when a settings reload occurs,
|
||||
these instanced changes are lost.
|
||||
|
||||
`TerminalSettings` can be used as a WinRT object that references (instead of copies) the relevant
|
||||
values of `CascadiaSettings`. This would prevent those instanced changes from being lost on a settings
|
||||
reload.
|
||||
|
||||
Since previewing commands like `setColorScheme` would require a clone of the existing `TerminalSettings`,
|
||||
a `Clone` API can be added on `TerminalSettings` to accomplish that. When passing by value,
|
||||
`TerminalSettings` can just overwrite the existing property (i.e.: color scheme). When passing
|
||||
by reference, a slightly more complex mechanism is required to override the value.
|
||||
|
||||
Now, instead of overwriting the value, we need to override the reference to a constant value
|
||||
(i.e.: `snapOnInput=true`) or a referenced value (i.e.: `colorScheme`).
|
||||
|
||||
### Layering Additional Settings
|
||||
As we begin to introduce more sources that affect the settings (via extensions or themes),
|
||||
we can introduce a `LayerSettings(String path)`. This layers the new settings file
|
||||
onto the existing `CascadiaSettings`. This is already done internally, we would just expose
|
||||
it via C++/WinRT.
|
||||
|
||||
```c++
|
||||
runtimeclass CascadiaSettings
|
||||
{
|
||||
// Load a settings file, and layer those changes on top of the existing CascadiaSettings
|
||||
void LayerSettings(String path);
|
||||
}
|
||||
```
|
||||
|
||||
### Settings UI: Modifying and Applying the Settings (DRAFT)
|
||||
|
||||
```c++
|
||||
runtimeclass CascadiaSettings
|
||||
{
|
||||
// Create a copy of the existing CascadiaSettings
|
||||
CascadiaSettings Clone();
|
||||
|
||||
// Compares object to "source" and applies changes to
|
||||
// the settings file at "outPath"
|
||||
void Save(String outPath);
|
||||
}
|
||||
```
|
||||
|
||||
The Settings UI will also have a reference to the `CascadiaSettings settings` from TerminalApp
|
||||
as `settingsSource`. When the Settings UI is opened up, the Settings UI will also have its own `CascadiaSettings settingsClone`
|
||||
that is a clone of TerminalApp's `CascadiaSettings`.
|
||||
```c++
|
||||
settingsClone = settingsSource.Clone()
|
||||
```
|
||||
|
||||
As the user navigates the Settings UI, the relevant contents of `settingsClone` will be retrieved and presented.
|
||||
As the user makes changes to the Settings UI, XAML will update `settingsClone` using XAML data binding.
|
||||
When the user saves/applies the changes in the XAML, `settingsClone.Save("settings.json")` is called;
|
||||
this compares the changes between `settingsClone` and `settingsSource`, then injects the changes (if any) to `settings.json`.
|
||||
|
||||
As mentioned earlier, TerminalApp detects a change to "settings.json" to update its `CascadiaSettings`.
|
||||
Since the above triggers a change to `settings.json`, TerminalApp will also update itself. When
|
||||
something like this occurs, `settingsSource` will automatically be updated too.
|
||||
|
||||
In the case that a user is simultaneously updating the settings file directly and the Settings UI,
|
||||
`settingsSource` and `settingsClone` can be compared to ensure that the Settings UI, the TerminalApp,
|
||||
and the settings files are all in sync.
|
||||
|
||||
**NOTE:** In the event that the user would want to export their current configuration, `Save`
|
||||
can be used to export the changes to a new file.
|
||||
|
||||
### Reserialization (DRAFT)
|
||||
|
||||
After deserializing the settings, injecting the new json into settings.json
|
||||
should not remove the existing comments or formatting.
|
||||
|
||||
The reserialization process takes place right after comparing the `settingsSource` and `settingsClone` objects.
|
||||
For each setting found in the diff, we go to the relevant part of the JSON and see if the key is already there.
|
||||
If it is, we update the value to be the one from `settingsClone`. Otherwise, we append the key/value pair
|
||||
at the end of the section (much like we do with dynamic profiles in `profiles`).
|
||||
|
||||
## Resources
|
||||
|
||||
- [Preview Commands](https://github.com/microsoft/terminal/issues/6689)
|
||||
- [New JSON Utils](https://github.com/microsoft/terminal/pull/6590)
|
||||
- [Spec: Settings UI](https://github.com/microsoft/terminal/pull/6720)
|
||||
BIN
doc/specs/#885 - Terminal Settings Model/Inheritance-DAG.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
doc/specs/#885 - Terminal Settings Model/Inheritance-DAG.vsdx
Normal file
@@ -1,11 +1,11 @@
|
||||
|
||||
# Branches in Openconsole
|
||||
|
||||
In Openconsole, `dev/main` is the master branch for the repo.
|
||||
In OpenConsole, `dev/main` is the primary branch for the repo.
|
||||
|
||||
Any branch that begins with `dev/` is recognized by our CI system and will automatically run x86 and amd64 builds and run our unit and feature tests. For feature branches the pattern we use is `dev/<alias>/<whatever you want here>`. ex. `dev/austdi/SomeCoolUnicodeFeature`. The important parts are the dev prefix and your alias.
|
||||
|
||||
`inbox` is a special branch that coordinates Openconsole code to the main OS repo.
|
||||
`inbox` is a special branch that coordinates OpenConsole code to the main OS repo.
|
||||
|
||||
The code will be checked into the OS repo at `/onecore/windows/core/console/open`. It would be prudent to make sure that directory builds in razzle with your submitted changes.
|
||||
|
||||
|
||||
@@ -22,15 +22,14 @@ Below is the schedule for when milestones will be included in release builds of
|
||||
| Milestone End Date | Milestone Name | Preview Release Blog Post |
|
||||
| ------------------ | -------------- | ------------------------- |
|
||||
| 2020-06-18 | [1.1] in Windows Terminal Preview | [Windows Terminal Preview 1.1 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-1-release/) |
|
||||
| 2020-07-31 | [1.2] in Windows Terminal Preview<br>[1.1] in Windows Terminal | |
|
||||
| 2020-08-31 | 1.3 in Windows Terminal Preview<br>[1.2] in Windows Terminal | |
|
||||
| 2020-09-30 | 1.4 in Windows Terminal Preview<br>1.3 in Windows Terminal | |
|
||||
| 2020-10-31 | 1.5 in Windows Terminal Preview<br>1.4 in Windows Terminal | |
|
||||
| 2020-11-30 | 1.6 in Windows Terminal Preview<br>1.5 in Windows Terminal | |
|
||||
| 2020-12-31 | 1.7 in Windows Terminal Preview<br>1.6 in Windows Terminal | |
|
||||
| 2021-01-31 | 1.8 in Windows Terminal Preview<br>1.7 in Windows Terminal | |
|
||||
| 2021-02-28 | 1.9 in Windows Terminal Preview<br>1.8 in Windows Terminal | |
|
||||
| 2021-03-31 | 1.10 in Windows Terminal Preview<br>1.9 in Windows Terminal | |
|
||||
| 2020-07-31 | [1.2] in Windows Terminal Preview<br>[1.1] in Windows Terminal | [Windows Terminal Preview 1.2 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-2-release/) |
|
||||
| 2020-08-31 | [1.3] in Windows Terminal Preview<br>[1.2] in Windows Terminal | [Windows Terminal Preview 1.3 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-3-release/) |
|
||||
| 2020-09-30 | [1.4] in Windows Terminal Preview<br>[1.3] in Windows Terminal | [Windows Terminal Preview 1.4 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-4-release/) |
|
||||
| 2020-11-30 | [1.5] in Windows Terminal Preview<br>[1.4] in Windows Terminal | |
|
||||
| 2020-12-31 | 1.6 in Windows Terminal Preview<br>[1.5] in Windows Terminal | |
|
||||
| 2021-01-31 | 1.7 in Windows Terminal Preview<br>1.6 in Windows Terminal | |
|
||||
| 2021-02-28 | 1.8 in Windows Terminal Preview<br>1.8 in Windows Terminal | |
|
||||
| 2021-03-31 | 1.9 in Windows Terminal Preview<br>1.9 in Windows Terminal | |
|
||||
| 2021-04-30 | 2.0 RC in Windows Terminal Preview<br>2.0 RC in Windows Terminal | |
|
||||
| 2021-05-31 | [2.0] in Windows Terminal Preview<br>[2.0] in Windows Terminal | |
|
||||
|
||||
@@ -50,11 +49,11 @@ The following are a list of the key scenarios we're aiming to deliver for Termin
|
||||
|
||||
| Priority\* | Scenario | Description/Notes |
|
||||
| ---------- | -------- | ----------------- |
|
||||
| 0 | Settings UI | A user interface that connects to settings.json. This provides a way for people to edit their settings without having to edit a JSON file.<br><br>Issue: [#1564] |
|
||||
| 0 | Command palette | A popup menu to list possible actions and commands.<br><br>Issues: [#5400], [#2046]<br>Spec: [#2193] |
|
||||
| 0 | Settings UI | A user interface that connects to settings.json. This provides a way for people to edit their settings without having to edit a JSON file.<br><br>Issue: [#1564]<br>Specs: [#6720], [#6904]<br>Implementation: [#7283], [#7370] |
|
||||
| 0 | Command palette | A popup menu to list possible actions and commands.<br><br>Issues: [#5400], [#2046]<br>Spec: [#2193]<br>Implementation: [#6635] |
|
||||
| 1 | Tab tear-off | The ability to tear a tab out of the current window and spawn a new window or attach it to a separate window.<br><br>Issue: [#1256]<br>Spec: [#2080] |
|
||||
| 1 | Clickable links | Hyperlinking any links that appear in the text buffer. When clicking on the link, the link will open in your default browser.<br><br>Issue: [#574] |
|
||||
| 1 | Default terminal | If a command-line application is spawned, it should open in Windows Terminal (if installed) or your preferred terminal<br><br>Issue: [#492]<br>Spec: [#2080] |
|
||||
| 1 | Clickable links | Hyperlinking any links that appear in the text buffer. When clicking on the link, the link will open in your default browser.<br><br>Issue: [#574]<br>Implementation: [#7251] |
|
||||
| 1 | Default terminal | If a command-line application is spawned, it should open in Windows Terminal (if installed) or your preferred terminal<br><br>Issue: [#492]<br>Spec: [#2080], [#7414] |
|
||||
| 1 | Overall theme support | Tab coloring, title bar coloring, pane border coloring, pane border width, definition of what makes a theme<br><br>Issue: [#3327]<br>Spec: [#5772] |
|
||||
| 1 | Open tab as admin/other user | Open tab in existing Windows Terminal instance as admin (if Terminal was run unelevated) or as another user.<br><br>Issue: [#5000] |
|
||||
| 1 | Traditional opacity | Have a transparent background without the acrylic blur.<br><br>Issue: [#603] |
|
||||
@@ -62,7 +61,7 @@ The following are a list of the key scenarios we're aiming to deliver for Termin
|
||||
| 2 | Infinite scrollback | Have an infinite history for the text buffer.<br><br>Issue: [#1410] |
|
||||
| 2 | Pane management | All issues listed out in the original issue. Some features include pane resizing with mouse, pane zooming, and opening a pane by prompting which profile to use.<br><br>Issue: [#1000] |
|
||||
| 2 | Theme marketplace | Marketplace for creation and distribution of themes.<br>Dependent on overall theming |
|
||||
| 2 | Jump list | Show profiles from task bar (on right click)/start menu.<br><br>Issue: [#576] |
|
||||
| 2 | Jump list | Show profiles from task bar (on right click)/start menu.<br><br>Issue: [#576]<br>Implementation: [#7515] |
|
||||
| 2 | Open with multiple tabs | A setting that allows Windows Terminal to launch with a specific tab configuration (not using only command line arguments).<br><br>Issue: [#756] |
|
||||
| 3 | Open in Windows Terminal | Functionality to right click on a file or folder and select Open in Windows Terminal.<br><br>Issue: [#1060]<br>Implementation: [#6100] |
|
||||
| 3 | Session restoration | Launch Windows Terminal and the previous session is restored with the proper tab and pane configuration and starting directories.<br><br>Issues: [#961], [#960], [#766] |
|
||||
@@ -80,16 +79,26 @@ Feature Notes:
|
||||
|
||||
[1.1]: https://github.com/microsoft/terminal/milestone/24
|
||||
[1.2]: https://github.com/microsoft/terminal/milestone/25
|
||||
[1.3]: https://github.com/microsoft/terminal/milestone/26
|
||||
[1.4]: https://github.com/microsoft/terminal/milestone/28
|
||||
[1.5]: https://github.com/microsoft/terminal/milestone/30
|
||||
[2.0]: https://github.com/microsoft/terminal/milestone/22
|
||||
[#1564]: https://github.com/microsoft/terminal/issues/1564
|
||||
[#6720]: https://github.com/microsoft/terminal/pull/6720
|
||||
[#6904]: https://github.com/microsoft/terminal/pull/6904
|
||||
[#7283]: https://github.com/microsoft/terminal/pull/7283
|
||||
[#7370]: https://github.com/microsoft/terminal/pull/7370
|
||||
[#5400]: https://github.com/microsoft/terminal/issues/5400
|
||||
[#2046]: https://github.com/microsoft/terminal/issues/2046
|
||||
[#2193]: https://github.com/microsoft/terminal/pull/2193
|
||||
[#6635]: https://github.com/microsoft/terminal/pull/6635
|
||||
[#1256]: https://github.com/microsoft/terminal/issues/1256
|
||||
[#2080]: https://github.com/microsoft/terminal/pull/2080
|
||||
[#574]: https://github.com/microsoft/terminal/issues/574
|
||||
[#7251]: https://github.com/microsoft/terminal/pull/7251
|
||||
[#492]: https://github.com/microsoft/terminal/issues/492
|
||||
[#2080]: https://github.com/microsoft/terminal/pull/2080
|
||||
[#7414]: https://github.com/microsoft/terminal/pull/7414
|
||||
[#3327]: https://github.com/microsoft/terminal/issues/3327
|
||||
[#5772]: https://github.com/microsoft/terminal/pull/5772
|
||||
[#5000]: https://github.com/microsoft/terminal/issues/5000
|
||||
@@ -100,6 +109,7 @@ Feature Notes:
|
||||
[#1410]: https://github.com/microsoft/terminal/issues/1410
|
||||
[#1000]: https://github.com/microsoft/terminal/issues/1000
|
||||
[#576]: https://github.com/microsoft/terminal/issues/576
|
||||
[#7515]: https://github.com/microsoft/terminal/pull/7515
|
||||
[#756]: https://github.com/microsoft/terminal/issues/756
|
||||
[#1060]: https://github.com/microsoft/terminal/issues/1060
|
||||
[#6100]: https://github.com/microsoft/terminal/pull/6100
|
||||
|
||||
@@ -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,51 +52,53 @@ 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"
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
For more details, see [this page](https://www.msys2.org/docs/terminals/#windows-terminal) on the MSYS2 documentation.
|
||||
|
||||
## Developer Command Prompt for Visual Studio
|
||||
|
||||
@@ -110,9 +106,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%"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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/).
|
||||
|
||||
434
oss/interval_tree/IntervalTree.h
Normal file
@@ -0,0 +1,434 @@
|
||||
#ifndef __INTERVAL_TREE_H
|
||||
#define __INTERVAL_TREE_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
||||
namespace interval_tree
|
||||
{
|
||||
#endif
|
||||
template<class Scalar, typename Value>
|
||||
class Interval
|
||||
{
|
||||
public:
|
||||
Scalar start;
|
||||
Scalar stop;
|
||||
Value value;
|
||||
Interval(const Scalar& s, const Scalar& e, const Value& v) :
|
||||
start(std::min(s, e)), stop(std::max(s, e)), value(v)
|
||||
{
|
||||
}
|
||||
|
||||
Interval()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator==(const Interval& other) const noexcept
|
||||
{
|
||||
return start == other.start &&
|
||||
stop == other.stop &&
|
||||
value == other.value;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const Interval& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Scalar, typename Value>
|
||||
Value intervalStart(const Interval<Scalar, Value>& i)
|
||||
{
|
||||
return i.start;
|
||||
}
|
||||
|
||||
template<class Scalar, typename Value>
|
||||
Value intervalStop(const Interval<Scalar, Value>& i)
|
||||
{
|
||||
return i.stop;
|
||||
}
|
||||
|
||||
template<class Scalar, typename Value>
|
||||
std::ostream& operator<<(std::ostream& out, const Interval<Scalar, Value>& i)
|
||||
{
|
||||
out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
|
||||
return out;
|
||||
}
|
||||
|
||||
template<class Scalar, class Value>
|
||||
class IntervalTree
|
||||
{
|
||||
public:
|
||||
typedef Interval<Scalar, Value> interval;
|
||||
typedef std::vector<interval> interval_vector;
|
||||
|
||||
struct IntervalStartCmp
|
||||
{
|
||||
bool operator()(const interval& a, const interval& b)
|
||||
{
|
||||
return a.start < b.start;
|
||||
}
|
||||
};
|
||||
|
||||
struct IntervalStopCmp
|
||||
{
|
||||
bool operator()(const interval& a, const interval& b)
|
||||
{
|
||||
return a.stop < b.stop;
|
||||
}
|
||||
};
|
||||
|
||||
IntervalTree() :
|
||||
left(nullptr), right(nullptr), center()
|
||||
{
|
||||
}
|
||||
|
||||
~IntervalTree() = default;
|
||||
|
||||
std::unique_ptr<IntervalTree> clone() const
|
||||
{
|
||||
return std::unique_ptr<IntervalTree>(new IntervalTree(*this));
|
||||
}
|
||||
|
||||
IntervalTree(const IntervalTree& other) :
|
||||
intervals(other.intervals),
|
||||
left(other.left ? other.left->clone() : nullptr),
|
||||
right(other.right ? other.right->clone() : nullptr),
|
||||
center(other.center)
|
||||
{
|
||||
}
|
||||
|
||||
IntervalTree& operator=(IntervalTree&&) = default;
|
||||
IntervalTree(IntervalTree&&) = default;
|
||||
|
||||
IntervalTree& operator=(const IntervalTree& other)
|
||||
{
|
||||
center = other.center;
|
||||
intervals = other.intervals;
|
||||
left = other.left ? other.left->clone() : nullptr;
|
||||
right = other.right ? other.right->clone() : nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntervalTree(
|
||||
interval_vector&& ivals,
|
||||
std::size_t depth = 16,
|
||||
std::size_t minbucket = 64,
|
||||
std::size_t maxbucket = 512,
|
||||
Scalar leftextent = {},
|
||||
Scalar rightextent = {}) :
|
||||
left(nullptr), right(nullptr)
|
||||
{
|
||||
--depth;
|
||||
const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(), IntervalStopCmp());
|
||||
const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(), IntervalStartCmp());
|
||||
if (!ivals.empty())
|
||||
{
|
||||
center = (minmaxStart.first->start + minmaxStop.second->stop) / 2;
|
||||
}
|
||||
if (leftextent == Scalar{} && rightextent == Scalar{})
|
||||
{
|
||||
// sort intervals by start
|
||||
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp()));
|
||||
}
|
||||
if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket))
|
||||
{
|
||||
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
|
||||
intervals = std::move(ivals);
|
||||
assert(is_valid().first);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Scalar leftp = Scalar{};
|
||||
Scalar rightp = Scalar{};
|
||||
|
||||
if (leftextent != Scalar{} || rightextent != Scalar{})
|
||||
{
|
||||
leftp = leftextent;
|
||||
rightp = rightextent;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftp = ivals.front().start;
|
||||
rightp = std::max_element(ivals.begin(), ivals.end(), IntervalStopCmp())->stop;
|
||||
}
|
||||
|
||||
interval_vector lefts;
|
||||
interval_vector rights;
|
||||
|
||||
for (typename interval_vector::const_iterator i = ivals.begin();
|
||||
i != ivals.end();
|
||||
++i)
|
||||
{
|
||||
const interval& interval = *i;
|
||||
if (interval.stop < center)
|
||||
{
|
||||
lefts.push_back(interval);
|
||||
}
|
||||
else if (interval.start > center)
|
||||
{
|
||||
rights.push_back(interval);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(interval.start <= center);
|
||||
assert(center <= interval.stop);
|
||||
intervals.push_back(interval);
|
||||
}
|
||||
}
|
||||
|
||||
if (!lefts.empty())
|
||||
{
|
||||
left.reset(new IntervalTree(std::move(lefts),
|
||||
depth,
|
||||
minbucket,
|
||||
maxbucket,
|
||||
leftp,
|
||||
center));
|
||||
}
|
||||
if (!rights.empty())
|
||||
{
|
||||
right.reset(new IntervalTree(std::move(rights),
|
||||
depth,
|
||||
minbucket,
|
||||
maxbucket,
|
||||
center,
|
||||
rightp));
|
||||
}
|
||||
}
|
||||
assert(is_valid().first);
|
||||
}
|
||||
|
||||
// Call f on all intervals near the range [start, stop]:
|
||||
template<class UnaryFunction>
|
||||
void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const
|
||||
{
|
||||
if (!intervals.empty() && !(stop < intervals.front().start))
|
||||
{
|
||||
for (auto& i : intervals)
|
||||
{
|
||||
f(i);
|
||||
}
|
||||
}
|
||||
if (left && start <= center)
|
||||
{
|
||||
left->visit_near(start, stop, f);
|
||||
}
|
||||
if (right && stop >= center)
|
||||
{
|
||||
right->visit_near(start, stop, f);
|
||||
}
|
||||
}
|
||||
|
||||
// Call f on all intervals crossing pos
|
||||
template<class UnaryFunction>
|
||||
void visit_overlapping(const Scalar& pos, UnaryFunction f) const
|
||||
{
|
||||
visit_overlapping(pos, pos, f);
|
||||
}
|
||||
|
||||
// Call f on all intervals overlapping [start, stop]
|
||||
template<class UnaryFunction>
|
||||
void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const
|
||||
{
|
||||
auto filterF = [&](const interval& interval) {
|
||||
if (interval.stop >= start && interval.start <= stop)
|
||||
{
|
||||
// Only apply f if overlapping
|
||||
f(interval);
|
||||
}
|
||||
};
|
||||
visit_near(start, stop, filterF);
|
||||
}
|
||||
|
||||
// Call f on all intervals contained within [start, stop]
|
||||
template<class UnaryFunction>
|
||||
void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const
|
||||
{
|
||||
auto filterF = [&](const interval& interval) {
|
||||
if (start <= interval.start && interval.stop <= stop)
|
||||
{
|
||||
f(interval);
|
||||
}
|
||||
};
|
||||
visit_near(start, stop, filterF);
|
||||
}
|
||||
|
||||
interval_vector findOverlapping(const Scalar& start, const Scalar& stop) const
|
||||
{
|
||||
interval_vector result;
|
||||
visit_overlapping(start, stop, [&](const interval& interval) {
|
||||
result.emplace_back(interval);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
interval_vector findContained(const Scalar& start, const Scalar& stop) const
|
||||
{
|
||||
interval_vector result;
|
||||
visit_contained(start, stop, [&](const interval& interval) {
|
||||
result.push_back(interval);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
if (left && !left->empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!intervals.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (right && !right->empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class UnaryFunction>
|
||||
void visit_all(UnaryFunction f) const
|
||||
{
|
||||
if (left)
|
||||
{
|
||||
left->visit_all(f);
|
||||
}
|
||||
std::for_each(intervals.begin(), intervals.end(), f);
|
||||
if (right)
|
||||
{
|
||||
right->visit_all(f);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Scalar, Scalar> extentBruitForce() const
|
||||
{
|
||||
struct Extent
|
||||
{
|
||||
std::pair<Scalar, Scalar> x = { std::numeric_limits<Scalar>::max(),
|
||||
std::numeric_limits<Scalar>::min() };
|
||||
void operator()(const interval& interval)
|
||||
{
|
||||
x.first = std::min(x.first, interval.start);
|
||||
x.second = std::max(x.second, interval.stop);
|
||||
}
|
||||
};
|
||||
Extent extent;
|
||||
|
||||
visit_all([&](const interval& interval) { extent(interval); });
|
||||
return extent.x;
|
||||
}
|
||||
|
||||
// Check all constraints.
|
||||
// If first is false, second is invalid.
|
||||
std::pair<bool, std::pair<Scalar, Scalar>> is_valid() const
|
||||
{
|
||||
const auto minmaxStop = std::minmax_element(intervals.begin(), intervals.end(), IntervalStopCmp());
|
||||
const auto minmaxStart = std::minmax_element(intervals.begin(), intervals.end(), IntervalStartCmp());
|
||||
|
||||
std::pair<bool, std::pair<Scalar, Scalar>> result = { true, { std::numeric_limits<Scalar>::max(), std::numeric_limits<Scalar>::min() } };
|
||||
if (!intervals.empty())
|
||||
{
|
||||
result.second.first = std::min(result.second.first, minmaxStart.first->start);
|
||||
result.second.second = std::min(result.second.second, minmaxStop.second->stop);
|
||||
}
|
||||
if (left)
|
||||
{
|
||||
auto valid = left->is_valid();
|
||||
result.first &= valid.first;
|
||||
result.second.first = std::min(result.second.first, valid.second.first);
|
||||
result.second.second = std::min(result.second.second, valid.second.second);
|
||||
if (!result.first)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (valid.second.second >= center)
|
||||
{
|
||||
result.first = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
auto valid = right->is_valid();
|
||||
result.first &= valid.first;
|
||||
result.second.first = std::min(result.second.first, valid.second.first);
|
||||
result.second.second = std::min(result.second.second, valid.second.second);
|
||||
if (!result.first)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (valid.second.first <= center)
|
||||
{
|
||||
result.first = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp()))
|
||||
{
|
||||
result.first = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const IntervalTree& itree)
|
||||
{
|
||||
return writeOut(os, itree);
|
||||
}
|
||||
|
||||
friend std::ostream& writeOut(std::ostream& os, const IntervalTree& itree, std::size_t depth = 0)
|
||||
{
|
||||
auto pad = [&]() { for (std::size_t i = 0; i != depth; ++i) { os << ' '; } };
|
||||
pad();
|
||||
os << "center: " << itree.center << '\n';
|
||||
for (const interval& inter : itree.intervals)
|
||||
{
|
||||
pad();
|
||||
os << inter << '\n';
|
||||
}
|
||||
if (itree.left)
|
||||
{
|
||||
pad();
|
||||
os << "left:\n";
|
||||
writeOut(os, *itree.left, depth + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pad();
|
||||
os << "left: nullptr\n";
|
||||
}
|
||||
if (itree.right)
|
||||
{
|
||||
pad();
|
||||
os << "right:\n";
|
||||
writeOut(os, *itree.right, depth + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pad();
|
||||
os << "right: nullptr\n";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
interval_vector intervals;
|
||||
std::unique_ptr<IntervalTree> left;
|
||||
std::unique_ptr<IntervalTree> right;
|
||||
Scalar center;
|
||||
};
|
||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
17
oss/interval_tree/MAINTAINER_README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Notes for Future Maintainers
|
||||
|
||||
This was originally imported by @PankajBhojwani in September 2020.
|
||||
|
||||
The provenance information (where it came from and which commit) is stored in the file `cgmanifest.json` in the same directory as this readme.
|
||||
Please update the provenance information in that file when ingesting an updated version of the dependent library.
|
||||
That provenance file is automatically read and inventoried by Microsoft systems to ensure compliance with appropiate governance standards.
|
||||
|
||||
## What should be done to update this in the future?
|
||||
|
||||
1. Go to ekg/intervaltreerepository on GitHub.
|
||||
2. Take the file IntervalTree.h wholesale and drop it into the directory here.
|
||||
3. Don't change anything about it.
|
||||
4. Validate that the license in the root of the repository didn't change and update it if so. It is sitting in the same directory as this readme.
|
||||
If it changed dramatically, ensure that it is still compatible with our license scheme. Also update the NOTICE file in the root of our repository to declare the third-party usage.
|
||||
5. Submit the pull.
|
||||
|
||||
13
oss/interval_tree/cgmanifest.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{"Registrations":[
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/ekg/intervaltree",
|
||||
"commitHash": "b90527f9e6d51cd36ecbb50429e4524d3a418ea5"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
7
oss/xorg_apps_rgb/MAINTAINER_README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### Notes for Future Maintainers
|
||||
|
||||
This manifest anchors our usage of rgb.txt from the X11 distribution.
|
||||
|
||||
The provenance information (where it came from and which commit) is stored in the file `cgmanifest.json` in the same directory as this readme.
|
||||
Please update the provenance information in that file when ingesting an updated version of the dependent library.
|
||||
That provenance file is automatically read and inventoried by Microsoft systems to ensure compliance with appropiate governance standards.
|
||||
13
oss/xorg_apps_rgb/cgmanifest.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{"Registrations":[
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://gitlab.freedesktop.org/xorg/app/rgb.git",
|
||||
"commitHash": "97820e748eb496a1f6d3fc3bf89688f0ce1f64f9"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
BIN
res/Cascadia.ttf
@@ -2,20 +2,20 @@
|
||||
|
||||
## Images
|
||||
|
||||
The images in this directory do not fall under the same [license](https://raw.githubusercontent.com/microsoft/terminal/master/LICENSE) as the rest
|
||||
The images in this directory do not fall under the same [license](https://raw.githubusercontent.com/microsoft/terminal/main/LICENSE) as the rest
|
||||
of the Windows Terminal code.
|
||||
|
||||
Please consult the [license](./LICENSE) in this directory for terms applicable to the image assets in this directory.
|
||||
|
||||
## Fonts
|
||||
|
||||
The fonts in this directory do not fall under the same [license](https://raw.githubusercontent.com/microsoft/terminal/master/LICENSE) as the rest
|
||||
The fonts in this directory do not fall under the same [license](https://raw.githubusercontent.com/microsoft/terminal/main/LICENSE) as the rest
|
||||
of the Windows Terminal code.
|
||||
|
||||
Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadia-code/master/LICENSE) in the
|
||||
Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadia-code/main/LICENSE) in the
|
||||
[microsoft/cascadia-code](https://github.com/microsoft/cascadia-code) repository for terms applicable to the fonts in this directory.
|
||||
|
||||
### Fonts Included
|
||||
|
||||
* Cascadia Code, Cascadia Mono (2007.01)
|
||||
* from microsoft/cascadia-code@311cc603f30635da704b6a7d13050e245e61667b
|
||||
* Cascadia Code, Cascadia Mono (2009.21)
|
||||
* from microsoft/cascadia-code@32f84124db1970fa5d032f0fe9019e6922961beb
|
||||
|
||||
@@ -24,6 +24,7 @@ Param(
|
||||
[string]$Path,
|
||||
[string]$Destination,
|
||||
[int[]]$Altforms = (16, 20, 24, 30, 32, 36, 40, 48, 60, 64, 72, 80, 96, 256),
|
||||
[int[]]$Win32IconSizes = (16, 20, 24, 32, 48, 64, 256),
|
||||
[switch]$Unplated = $true,
|
||||
[float[]]$Scales = (1.0, 1.25, 1.5, 2.0, 4.0),
|
||||
[string]$HighContrastPath = "",
|
||||
@@ -115,6 +116,7 @@ If (-Not [string]::IsNullOrEmpty($Destination)) {
|
||||
$TranslatedOutDir = "."
|
||||
}
|
||||
|
||||
$intermediates = [System.Collections.Concurrent.ConcurrentBag[PSCustomObject]]::new()
|
||||
$intermediateFiles = [System.Collections.Concurrent.ConcurrentBag[string]]::new()
|
||||
|
||||
# Generate the base icons
|
||||
@@ -136,6 +138,11 @@ $allSizes | ForEach-Object -Parallel {
|
||||
}
|
||||
|
||||
($using:intermediateFiles).Add($intermediateStandardNt)
|
||||
($using:intermediates).Add([PSCustomObject]@{
|
||||
Contrast = "standard"
|
||||
Size = $sz
|
||||
PathWSL = $intermediateStandardWsl
|
||||
})
|
||||
|
||||
If ($svgContrastWsl -Ne $null) {
|
||||
$intermediateBlackNt = "$destinationNt\_intermediate.black.$($sz).png"
|
||||
@@ -158,9 +165,28 @@ $allSizes | ForEach-Object -Parallel {
|
||||
|
||||
($using:intermediateFiles).Add($intermediateBlackNt)
|
||||
($using:intermediateFiles).Add($intermediateWhiteNt)
|
||||
($using:intermediates).Add([PSCustomObject]@{
|
||||
Contrast = "black"
|
||||
Size = $sz
|
||||
PathWSL = $intermediateBlackWsl
|
||||
})
|
||||
($using:intermediates).Add([PSCustomObject]@{
|
||||
Contrast = "white"
|
||||
Size = $sz
|
||||
PathWSL = $intermediateWhiteWsl
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
$intermediates | ? { $_.Size -In $Win32IconSizes } | Group-Object Contrast | ForEach-Object -Parallel {
|
||||
$assetName = "terminal.ico"
|
||||
If ($_.Name -Ne "standard") {
|
||||
$assetName = "terminal_contrast-$($_.Name).ico"
|
||||
}
|
||||
Write-Host "Producing win32 .ico for contrast=$($_.Name) as $assetName"
|
||||
wsl convert $_.Group.PathWSL "$($using:TranslatedOutDir)/$assetName"
|
||||
}
|
||||
|
||||
# Once the base icons are done, splat them into the middles of larger canvases.
|
||||
$allAssetSizes | ForEach-Object -Parallel {
|
||||
$asset = $_
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 7.5 KiB |