mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-07 14:50:55 +00:00
Compare commits
218 Commits
dev/lhecke
...
dev/lhecke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6126532e71 | ||
|
|
a4445ed4cc | ||
|
|
f1ca1566a1 | ||
|
|
057183b651 | ||
|
|
fb8b120215 | ||
|
|
d115500cff | ||
|
|
c4c06dadad | ||
|
|
375d00d0cd | ||
|
|
b02316b37c | ||
|
|
8b7bb99160 | ||
|
|
acb06304c2 | ||
|
|
a62fb06b32 | ||
|
|
322fdd027c | ||
|
|
c150919bd0 | ||
|
|
2546c02adb | ||
|
|
63c3573a13 | ||
|
|
bc18348967 | ||
|
|
91e97c169e | ||
|
|
5d85eb3e24 | ||
|
|
a65d5f321f | ||
|
|
99193c9a3f | ||
|
|
28acc102a5 | ||
|
|
171a21ad48 | ||
|
|
306cb404dc | ||
|
|
f5b45c25c9 | ||
|
|
a93d99d0c1 | ||
|
|
bcc01d96bf | ||
|
|
17867af534 | ||
|
|
20dad62471 | ||
|
|
32f19ef437 | ||
|
|
f63e25b87c | ||
|
|
8b5c833b2b | ||
|
|
efbfb12145 | ||
|
|
306f31acf4 | ||
|
|
dc986e4489 | ||
|
|
65d2d3dcec | ||
|
|
9967851bf8 | ||
|
|
f9652983f1 | ||
|
|
5f5ef10571 | ||
|
|
71a6f26e6e | ||
|
|
8a9af94095 | ||
|
|
70e51ae28d | ||
|
|
ef32e3e487 | ||
|
|
9882154043 | ||
|
|
486f7ef644 | ||
|
|
85eee09854 | ||
|
|
ab7a2f10c5 | ||
|
|
0da37a134a | ||
|
|
91fd7d0101 | ||
|
|
204ebf3b19 | ||
|
|
e33de75402 | ||
|
|
17d24bf055 | ||
|
|
dd83ba62cf | ||
|
|
d4292d16cc | ||
|
|
a4ec8ec591 | ||
|
|
3538a9f72b | ||
|
|
5ed7dc2f63 | ||
|
|
0d353d8be5 | ||
|
|
abab8705fe | ||
|
|
654b755161 | ||
|
|
be9fc200c7 | ||
|
|
130c9fbd76 | ||
|
|
0c4751ba30 | ||
|
|
3b5e5cf5f1 | ||
|
|
7a1b6f9d2a | ||
|
|
8747a39a07 | ||
|
|
35240f263e | ||
|
|
0a4fc9b6e4 | ||
|
|
63b3820a18 | ||
|
|
264ef4ebda | ||
|
|
bdf2f6f274 | ||
|
|
adb04729bc | ||
|
|
12318d97d0 | ||
|
|
376737e54a | ||
|
|
b780b44528 | ||
|
|
86fb9b4478 | ||
|
|
65e19ddaf0 | ||
|
|
37100034bf | ||
|
|
55a9874d5c | ||
|
|
a7409ea4d3 | ||
|
|
28a1ecbdaa | ||
|
|
4bbfa0570a | ||
|
|
2ac5e8670a | ||
|
|
d14524cd4c | ||
|
|
e268c1c952 | ||
|
|
eb16eeb29e | ||
|
|
5a9f3529d7 | ||
|
|
18b0ecbb2a | ||
|
|
71a1a97a9a | ||
|
|
077d63e6a3 | ||
|
|
7cbe3190e1 | ||
|
|
db27348e27 | ||
|
|
83a2bc181a | ||
|
|
95e4d0bbe0 | ||
|
|
a608a91571 | ||
|
|
646edc7f8f | ||
|
|
7a8dd90294 | ||
|
|
59dcbbe0e9 | ||
|
|
a5c269b280 | ||
|
|
17cc109081 | ||
|
|
9e86c9811f | ||
|
|
0289cb043c | ||
|
|
19efcfee9d | ||
|
|
49c177f219 | ||
|
|
68b5e58754 | ||
|
|
16bac45714 | ||
|
|
188a2ae4c8 | ||
|
|
c2fde69ff5 | ||
|
|
798ab586f1 | ||
|
|
9892ade4e0 | ||
|
|
7fd476d9ed | ||
|
|
c0275018ea | ||
|
|
229ba89c83 | ||
|
|
b6593e713e | ||
|
|
7e2be66ec5 | ||
|
|
4b58fc6c8e | ||
|
|
d0d3039963 | ||
|
|
d8c7719bfb | ||
|
|
e1c69a99ce | ||
|
|
d496a5fb80 | ||
|
|
08f30330d1 | ||
|
|
64b5b2884a | ||
|
|
1745857407 | ||
|
|
f2c3ddd105 | ||
|
|
0b9f041706 | ||
|
|
27e1081c8c | ||
|
|
ee17d6c55e | ||
|
|
544cdd78af | ||
|
|
0144cdd7bc | ||
|
|
af8e20c3b6 | ||
|
|
d801375883 | ||
|
|
4efee36376 | ||
|
|
775e7ebe1f | ||
|
|
145c4d3641 | ||
|
|
5aadddaea9 | ||
|
|
d0c228e95a | ||
|
|
6ecdae796f | ||
|
|
f6e1126b77 | ||
|
|
4ee21b38b5 | ||
|
|
70ad67053d | ||
|
|
47728dc38b | ||
|
|
4145f18768 | ||
|
|
aafb91745e | ||
|
|
59aaba7c5b | ||
|
|
8521aae889 | ||
|
|
f6425dbd59 | ||
|
|
b9cbf0f24c | ||
|
|
6489f6b39d | ||
|
|
1669036e59 | ||
|
|
4c795b5bcd | ||
|
|
828c1ebf66 | ||
|
|
3eae898ddc | ||
|
|
3e0b3e3925 | ||
|
|
057d1334db | ||
|
|
f1a868517c | ||
|
|
ac2b0e744c | ||
|
|
1b143e34a8 | ||
|
|
4382a17352 | ||
|
|
cc2ba5350d | ||
|
|
3fc5286052 | ||
|
|
7073ec01bf | ||
|
|
198c11f36d | ||
|
|
cf193858f6 | ||
|
|
310814bb30 | ||
|
|
aef2dbd076 | ||
|
|
6183b27547 | ||
|
|
b772b2da57 | ||
|
|
74748394c1 | ||
|
|
c7f30a86d7 | ||
|
|
e0fc3bcd0a | ||
|
|
2ecfac80e7 | ||
|
|
18dae6dae8 | ||
|
|
86ad3c84cb | ||
|
|
29a22c9e8a | ||
|
|
41f7ed73c1 | ||
|
|
d38bb906ec | ||
|
|
fc4a37ee91 | ||
|
|
c1bdcf8b97 | ||
|
|
75f3d4f3df | ||
|
|
d272fc4644 | ||
|
|
9b986a16cf | ||
|
|
059f7701f2 | ||
|
|
b5333f64e5 | ||
|
|
523edd7941 | ||
|
|
394b942a56 | ||
|
|
59248de1e4 | ||
|
|
2e91e9c6de | ||
|
|
3550e19751 | ||
|
|
4370da9549 | ||
|
|
f494d68f11 | ||
|
|
5f9624f6ea | ||
|
|
8daf89e318 | ||
|
|
1f3779e05a | ||
|
|
741633ef7a | ||
|
|
2fa8e766bb | ||
|
|
4bc34e490c | ||
|
|
37b0cfd32b | ||
|
|
4ddfc3eaf3 | ||
|
|
43535b0d1c | ||
|
|
d19aaf7ead | ||
|
|
5d300b20ed | ||
|
|
2f7f759af4 | ||
|
|
3830c62a81 | ||
|
|
2f41d23d6d | ||
|
|
6cff135f37 | ||
|
|
b53ddd1b47 | ||
|
|
0cbde94e4b | ||
|
|
c5e0908b98 | ||
|
|
60843faa9e | ||
|
|
5fb2518117 | ||
|
|
636be7e514 | ||
|
|
a132ba82e7 | ||
|
|
7aada2fd1e | ||
|
|
553ad121af | ||
|
|
154ac2b916 | ||
|
|
3c104440a8 | ||
|
|
b6feabe9cc | ||
|
|
a0624bedaa |
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"XamlStyler.Console": {
|
||||
"version": "3.2206.4",
|
||||
"version": "3.2311.2",
|
||||
"commands": [
|
||||
"xstyler"
|
||||
]
|
||||
|
||||
6
.github/actions/spelling/advice.md
vendored
6
.github/actions/spelling/advice.md
vendored
@@ -6,8 +6,6 @@
|
||||
|
||||
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
|
||||
|
||||
:warning: The command is written for posix shells. If it doesn't work for you, you can manually _add_ (one word per line) / _remove_ items to `expect.txt` and the `excludes.txt` files.
|
||||
|
||||
If the listed items are:
|
||||
|
||||
* ... **misspelled**, then please *correct* them instead of using the command.
|
||||
@@ -36,7 +34,9 @@ https://www.regexplanet.com/advanced/perl/) yours before committing to verify it
|
||||
|
||||
* well-formed pattern.
|
||||
|
||||
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
|
||||
If you can write a [pattern](
|
||||
https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
|
||||
) that would match it,
|
||||
try adding it to the `patterns.txt` file.
|
||||
|
||||
Patterns are Perl 5 Regular Expressions - you can [test](
|
||||
|
||||
9
.github/actions/spelling/allow/allow.txt
vendored
9
.github/actions/spelling/allow/allow.txt
vendored
@@ -1,3 +1,4 @@
|
||||
aci
|
||||
admins
|
||||
allcolors
|
||||
Apc
|
||||
@@ -8,11 +9,13 @@ breadcrumbs
|
||||
bsd
|
||||
calt
|
||||
ccmp
|
||||
ccon
|
||||
changelog
|
||||
clickable
|
||||
clig
|
||||
CMMI
|
||||
copyable
|
||||
Counterintuitively
|
||||
CtrlDToClose
|
||||
cybersecurity
|
||||
dalet
|
||||
@@ -52,6 +55,7 @@ hyperlinks
|
||||
iconify
|
||||
img
|
||||
inlined
|
||||
issuetitle
|
||||
It'd
|
||||
kje
|
||||
libfuzzer
|
||||
@@ -90,10 +94,13 @@ reserialize
|
||||
reserializes
|
||||
rlig
|
||||
runtimes
|
||||
servicebus
|
||||
shcha
|
||||
similaritytolerance
|
||||
slnt
|
||||
Sos
|
||||
ssh
|
||||
sustainability
|
||||
stakeholders
|
||||
sxn
|
||||
timeline
|
||||
@@ -115,7 +122,9 @@ vsdevcmd
|
||||
walkthrough
|
||||
walkthroughs
|
||||
We'd
|
||||
westus
|
||||
wildcards
|
||||
workarounds
|
||||
XBox
|
||||
YBox
|
||||
yeru
|
||||
|
||||
5
.github/actions/spelling/allow/apis.txt
vendored
5
.github/actions/spelling/allow/apis.txt
vendored
@@ -28,6 +28,7 @@ CYICON
|
||||
Dacl
|
||||
dataobject
|
||||
dcomp
|
||||
debugbreak
|
||||
delayimp
|
||||
DERR
|
||||
dlldata
|
||||
@@ -209,6 +210,7 @@ tlg
|
||||
TME
|
||||
tmp
|
||||
tmpdir
|
||||
tokeninfo
|
||||
tolower
|
||||
toupper
|
||||
TRACKMOUSEEVENT
|
||||
@@ -219,16 +221,19 @@ UFIELD
|
||||
ULARGE
|
||||
UOI
|
||||
UPDATEINIFILE
|
||||
urlmon
|
||||
userenv
|
||||
USEROBJECTFLAGS
|
||||
Vcpp
|
||||
Viewbox
|
||||
virtualalloc
|
||||
vsnwprintf
|
||||
wcsnlen
|
||||
wcsstr
|
||||
wcstoui
|
||||
WDJ
|
||||
winhttp
|
||||
wininet
|
||||
winmain
|
||||
winsta
|
||||
winstamin
|
||||
|
||||
4
.github/actions/spelling/allow/microsoft.txt
vendored
4
.github/actions/spelling/allow/microsoft.txt
vendored
@@ -4,6 +4,7 @@ advapi
|
||||
altform
|
||||
altforms
|
||||
appendwttlogging
|
||||
appinstaller
|
||||
appx
|
||||
appxbundle
|
||||
appxerror
|
||||
@@ -59,12 +60,13 @@ PRIINFO
|
||||
propkey
|
||||
pscustomobject
|
||||
QWORD
|
||||
rdpclip
|
||||
regedit
|
||||
resfiles
|
||||
robocopy
|
||||
SACLs
|
||||
segoe
|
||||
sdkddkver
|
||||
segoe
|
||||
Shobjidl
|
||||
sid
|
||||
Skype
|
||||
|
||||
1
.github/actions/spelling/allow/names.txt
vendored
1
.github/actions/spelling/allow/names.txt
vendored
@@ -6,6 +6,7 @@ bhoj
|
||||
Bhojwani
|
||||
Bluloco
|
||||
carlos
|
||||
craigloewen
|
||||
dhowett
|
||||
Diviness
|
||||
dsafa
|
||||
|
||||
202
.github/actions/spelling/candidate.patterns
vendored
202
.github/actions/spelling/candidate.patterns
vendored
@@ -1,23 +1,37 @@
|
||||
# marker to ignore all code on line
|
||||
^.*/\* #no-spell-check-line \*/.*$
|
||||
# marker for ignoring a comment to the end of the line
|
||||
// #no-spell-check.*$
|
||||
# marker to ignore all code on line
|
||||
^.*\bno-spell-check(?:-line|)(?:\s.*|)$
|
||||
|
||||
# https://cspell.org/configuration/document-settings/
|
||||
# cspell inline
|
||||
^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b
|
||||
|
||||
# patch hunk comments
|
||||
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
|
||||
# git index header
|
||||
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
|
||||
index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
|
||||
|
||||
# file permissions
|
||||
['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
|
||||
|
||||
# css url wrappings
|
||||
\burl\([^)]+\)
|
||||
|
||||
# cid urls
|
||||
(['"])cid:.*?\g{-1}
|
||||
|
||||
# data url in parens
|
||||
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
|
||||
#\(data:(?:[^) ][^)]*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
|
||||
|
||||
# data url in quotes
|
||||
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
|
||||
([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
|
||||
# data url
|
||||
data:[-a-zA-Z=;:/0-9+]*,\S*
|
||||
|
||||
# https/http/file urls
|
||||
(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]
|
||||
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
@@ -35,6 +49,9 @@ magnet:[?=:\w]+
|
||||
# asciinema
|
||||
\basciinema\.org/a/[0-9a-zA-Z]+
|
||||
|
||||
# asciinema v2
|
||||
^\[\d+\.\d+, "[io]", ".*"\]$
|
||||
|
||||
# apple
|
||||
\bdeveloper\.apple\.com/[-\w?=/]+
|
||||
# Apple music
|
||||
@@ -89,7 +106,7 @@ vpc-\w+
|
||||
# Google Drive
|
||||
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
|
||||
# Google Groups
|
||||
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)*
|
||||
\bgroups\.google\.com(?:/[a-z]+/(?:#!|)[^/\s"]+)*
|
||||
# Google Maps
|
||||
\bmaps\.google\.com/maps\?[\w&;=]*
|
||||
# Google themes
|
||||
@@ -117,6 +134,8 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
|
||||
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
|
||||
# GitHub SHAs
|
||||
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
|
||||
# GitHub SHA refs
|
||||
\[([0-9a-f]+)\]\(https://(?:www\.|)github.com/[-\w]+/[-\w]+/commit/\g{-1}[0-9a-f]*
|
||||
# GitHub wiki
|
||||
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
|
||||
# githubusercontent
|
||||
@@ -128,9 +147,9 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
|
||||
# git.io
|
||||
\bgit\.io/[0-9a-zA-Z]+
|
||||
# GitHub JSON
|
||||
"node_id": "[-a-zA-Z=;:/0-9+]*"
|
||||
"node_id": "[-a-zA-Z=;:/0-9+_]*"
|
||||
# Contributor
|
||||
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
|
||||
\[[^\]]+\]\(https://github\.com/[^/\s"]+/?\)
|
||||
# GHSA
|
||||
GHSA(?:-[0-9a-z]{4}){3}
|
||||
|
||||
@@ -143,8 +162,8 @@ GHSA(?:-[0-9a-z]{4}){3}
|
||||
# GitLab commits
|
||||
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
|
||||
|
||||
# binanace
|
||||
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
|
||||
# binance
|
||||
accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
|
||||
|
||||
# bitbucket diff
|
||||
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
|
||||
@@ -280,9 +299,9 @@ slack://[a-zA-Z0-9?&=]+
|
||||
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
|
||||
|
||||
# ipfs protocol
|
||||
ipfs://[0-9a-z]*
|
||||
ipfs://[0-9a-zA-Z]{3,}
|
||||
# ipfs url
|
||||
/ipfs/[0-9a-z]*
|
||||
/ipfs/[0-9a-zA-Z]{3,}
|
||||
|
||||
# w3
|
||||
\bw3\.org/[-0-9a-zA-Z/#.]+
|
||||
@@ -359,22 +378,33 @@ ipfs://[0-9a-z]*
|
||||
# tinyurl
|
||||
\btinyurl\.com/\w+
|
||||
|
||||
# codepen
|
||||
\bcodepen\.io/[\w/]+
|
||||
|
||||
# registry.npmjs.org
|
||||
\bregistry\.npmjs\.org/(?:@[^/"']+/|)[^/"']+/-/[-\w@.]+
|
||||
|
||||
# getopts
|
||||
\bgetopts\s+(?:"[^"]+"|'[^']+')
|
||||
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
|
||||
|
||||
# URL escaped characters
|
||||
\%[0-9A-F][A-F]
|
||||
\%[0-9A-F][A-F](?=[A-Za-z])
|
||||
# lower URL escaped characters
|
||||
\%[0-9a-f][a-f](?=[a-z]{2,})
|
||||
# IPv6
|
||||
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
|
||||
#\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
|
||||
|
||||
# c99 hex digits (not the full format, just one I've seen)
|
||||
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
|
||||
# Punycode
|
||||
\bxn--[-0-9a-z]+
|
||||
# sha
|
||||
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
|
||||
# sha-... -- uses a fancy capture
|
||||
(['"]|")[0-9a-f]{40,}\g{-1}
|
||||
(\\?['"]|")[0-9a-f]{40,}\g{-1}
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
# hex in url queries
|
||||
@@ -389,18 +419,21 @@ sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
|
||||
# Well known gpg keys
|
||||
.well-known/openpgpkey/[\w./]+
|
||||
|
||||
# pki
|
||||
-----BEGIN.*-----END
|
||||
|
||||
# uuid:
|
||||
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
|
||||
# hex digits including css/html color classes:
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
|
||||
# integrity
|
||||
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
|
||||
integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
|
||||
|
||||
# https://www.gnu.org/software/groff/manual/groff.html
|
||||
# man troff content
|
||||
\\f[BCIPR]
|
||||
# '
|
||||
\\\(aq
|
||||
# '/"
|
||||
\\\([ad]q
|
||||
|
||||
# .desktop mime types
|
||||
^MimeTypes?=.*$
|
||||
@@ -409,21 +442,33 @@ integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
|
||||
# Localized .desktop content
|
||||
Name\[[^\]]+\]=.*
|
||||
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
# IServiceProvider / isAThing
|
||||
\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
|
||||
# crypt
|
||||
"\$2[ayb]\$.{56}"
|
||||
(['"])\$2[ayb]\$.{56}\g{-1}
|
||||
|
||||
# scrypt / argon
|
||||
\$(?:scrypt|argon\d+[di]*)\$\S+
|
||||
|
||||
# Input to GitHub JSON
|
||||
content: "[-a-zA-Z=;:/0-9+]*="
|
||||
# go.sum
|
||||
\bh1:\S+
|
||||
|
||||
# Python stringprefix / binaryprefix
|
||||
# scala modules
|
||||
("[^"]+"\s*%%?\s*){2,3}"[^"]+"
|
||||
|
||||
# Input to GitHub JSON
|
||||
content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
|
||||
|
||||
# This does not cover multiline strings, if your repository has them,
|
||||
# you'll want to remove the `(?=.*?")` suffix.
|
||||
# The `(?=.*?")` suffix should limit the false positives rate
|
||||
# printf
|
||||
#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA]|p)(?=[a-zA-Z]{2,}))(?=[_a-zA-Z]+\b)(?!%)(?=.*?['"])
|
||||
|
||||
# Python string prefix / binary prefix
|
||||
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
|
||||
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
|
||||
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?=[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
|
||||
|
||||
# Regular expressions for (P|p)assword
|
||||
\([A-Z]\|[a-z]\)[a-z]+
|
||||
@@ -439,16 +484,35 @@ content: "[-a-zA-Z=;:/0-9+]*="
|
||||
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
|
||||
# javascript replace regex
|
||||
\.replace\(/[^/\s"]*/[gim]*\s*,
|
||||
# assign regex
|
||||
= /[^*]*?(?:[a-z]{3,}|[A-Z]{3,}|[A-Z][a-z]{2,}).*/
|
||||
# perl regex test
|
||||
[!=]~ (?:/.*/|m\{.*?\}|m<.*?>|m([|!/@#,;']).*?\g{-1})
|
||||
|
||||
# perl qr regex
|
||||
(?<!\$)\bqr(?:\{.*?\}|<.*?>|\(.*?\)|([|!/@#,;']).*?\g{-1})
|
||||
|
||||
# Go regular expressions
|
||||
regexp?\.MustCompile\(`[^`]*`\)
|
||||
|
||||
# regex choice
|
||||
\(\?:[^)]+\|[^)]+\)
|
||||
|
||||
# proto
|
||||
^\s*(\w+)\s\g{-1} =
|
||||
|
||||
# sed regular expressions
|
||||
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
|
||||
|
||||
# node packages
|
||||
(["'])\@[^/'" ]+/[^/'" ]+\g{-1}
|
||||
|
||||
# go install
|
||||
go install(?:\s+[a-z]+\.[-@\w/.]+)+
|
||||
|
||||
# jetbrains schema https://youtrack.jetbrains.com/issue/RSRP-489571
|
||||
urn:shemas-jetbrains-com
|
||||
|
||||
# kubernetes pod status lists
|
||||
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
|
||||
@@ -460,19 +524,47 @@ go install(?:\s+[a-z]+\.[-@\w/.]+)+
|
||||
-[0-9a-f]{10}-\w{5}\s
|
||||
|
||||
# posthog secrets
|
||||
posthog\.init\((['"])phc_[^"',]+\g{-1},
|
||||
([`'"])phc_[^"',]+\g{-1}
|
||||
|
||||
# xcode
|
||||
|
||||
# xcodeproject scenes
|
||||
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
|
||||
(?:Controller|destination|ID|id)="\w{3}-\w{2}-\w{3}"
|
||||
|
||||
# xcode api botches
|
||||
customObjectInstantitationMethod
|
||||
|
||||
# configure flags
|
||||
.* \| --\w{2,}.*?(?=\w+\s\w+)
|
||||
|
||||
# font awesome classes
|
||||
\.fa-[-a-z0-9]+
|
||||
|
||||
# bearer auth
|
||||
(['"])Bear[e][r] .*?\g{-1}
|
||||
|
||||
# basic auth
|
||||
(['"])Basic [-a-zA-Z=;:/0-9+]{3,}\g{-1}
|
||||
|
||||
# base64 encoded content
|
||||
#([`'"])[-a-zA-Z=;:/0-9+]+=\g{-1}
|
||||
# base64 encoded content in xml/sgml
|
||||
>[-a-zA-Z=;:/0-9+]+=</
|
||||
# base64 encoded content, possibly wrapped in mime
|
||||
#(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$)
|
||||
|
||||
# encoded-word
|
||||
=\?[-a-zA-Z0-9"*%]+\?[BQ]\?[^?]{0,75}\?=
|
||||
|
||||
# Time Zones
|
||||
\b(?:Africa|Atlantic|America|Antarctica|Asia|Australia|Europe|Indian|Pacific)(?:/\w+)+
|
||||
|
||||
# linux kernel info
|
||||
^(?:bugs|flags|Features)\s+:.*
|
||||
|
||||
# systemd mode
|
||||
systemd.*?running in system mode \([-+].*\)$
|
||||
|
||||
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
|
||||
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
|
||||
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
|
||||
@@ -483,32 +575,62 @@ customObjectInstantitationMethod
|
||||
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
|
||||
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
|
||||
|
||||
# highlighted letters
|
||||
\[[A-Z]\][a-z]+
|
||||
|
||||
# French
|
||||
# This corpus only had capital letters, but you probably want lowercase ones as well.
|
||||
\b[LN]'+[a-z]{2,}\b
|
||||
|
||||
# latex
|
||||
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
# latex (check-spelling <= 0.0.21)
|
||||
#\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
|
||||
# latex (check-spelling >= 0.0.22)
|
||||
\\\w{2,}\{
|
||||
|
||||
# eslint
|
||||
"varsIgnorePattern": ".+"
|
||||
|
||||
# Windows short paths
|
||||
[/\\][^/\\]{5,6}~\d{1,2}[/\\]
|
||||
|
||||
# in check-spelling@v0.0.22+, printf markers aren't automatically consumed
|
||||
# printf markers
|
||||
#(?<!\\)\\[nrt](?=[a-z]{2,})
|
||||
|
||||
# alternate markers if you run into latex and friends
|
||||
#(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*['"`])
|
||||
|
||||
# apache
|
||||
a2(?:en|dis)
|
||||
|
||||
# weak e-tag
|
||||
W/"[^"]+"
|
||||
|
||||
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
|
||||
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
|
||||
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
|
||||
#\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
|
||||
|
||||
# ignore long runs of a single character:
|
||||
\b([A-Za-z])\g{-1}{3,}\b
|
||||
# Note that the next example is no longer necessary if you are using
|
||||
# to match a string starting with a `#`, use a character-class:
|
||||
[#]backwards
|
||||
|
||||
# version suffix <word>v#
|
||||
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
|
||||
# Compiler flags (Scala)
|
||||
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
# Compiler flags
|
||||
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# Compiler flags (Unix, Java/Scala)
|
||||
# Use if you have things like `-Pdocker` and want to treat them as `docker`
|
||||
#(?:^|[\t ,>"'`=(])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# Compiler flags (Windows / PowerShell)
|
||||
# This is a subset of the more general compiler flags pattern.
|
||||
# It avoids matching `-Path` to prevent it from being treated as `ath`
|
||||
#(?:^|[\t ,"'`=(])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
|
||||
|
||||
# Compiler flags (linker)
|
||||
,-B
|
||||
|
||||
# curl arguments
|
||||
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
|
||||
# set arguments
|
||||
|
||||
59
.github/actions/spelling/excludes.txt
vendored
59
.github/actions/spelling/excludes.txt
vendored
@@ -1,21 +1,24 @@
|
||||
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
|
||||
(?:(?i)\.png$)
|
||||
(?:^|/)(?i)COPYRIGHT
|
||||
(?:^|/)(?i)LICEN[CS]E
|
||||
(?:^|/)3rdparty/
|
||||
(?:^|/)dirs$
|
||||
(?:^|/)go\.mod$
|
||||
(?:^|/)go\.sum$
|
||||
(?:^|/)package(?:-lock|)\.json$
|
||||
(?:^|/)Pipfile$
|
||||
(?:^|/)pyproject.toml
|
||||
(?:^|/)requirements(?:-dev|-doc|-test|)\.txt$
|
||||
(?:^|/)sources(?:|\.dep)$
|
||||
(?:^|/)vendor/
|
||||
\.a$
|
||||
\.ai$
|
||||
\.all-contributorsrc$
|
||||
\.avi$
|
||||
\.bmp$
|
||||
\.bz2$
|
||||
\.cer$
|
||||
\.class$
|
||||
\.coveragerc$
|
||||
\.crl$
|
||||
\.crt$
|
||||
\.csr$
|
||||
@@ -27,11 +30,15 @@
|
||||
\.eps$
|
||||
\.exe$
|
||||
\.gif$
|
||||
\.git-blame-ignore-revs$
|
||||
\.gitattributes$
|
||||
\.gitignore$
|
||||
\.gitkeep$
|
||||
\.graffle$
|
||||
\.gz$
|
||||
\.icns$
|
||||
\.ico$
|
||||
\.ipynb$
|
||||
\.jar$
|
||||
\.jks$
|
||||
\.jpeg$
|
||||
@@ -41,61 +48,62 @@
|
||||
\.lock$
|
||||
\.map$
|
||||
\.min\..
|
||||
\.mo$
|
||||
\.mod$
|
||||
\.mp3$
|
||||
\.mp4$
|
||||
\.o$
|
||||
\.ocf$
|
||||
\.otf$
|
||||
\.p12$
|
||||
\.parquet$
|
||||
\.pbxproj$
|
||||
\.pdf$
|
||||
\.pem$
|
||||
\.pfx$
|
||||
\.png$
|
||||
\.psd$
|
||||
\.pyc$
|
||||
\.pylintrc$
|
||||
\.qm$
|
||||
\.runsettings$
|
||||
\.s$
|
||||
\.sig$
|
||||
\.so$
|
||||
\.svg$
|
||||
\.svgz$
|
||||
\.svgz?$
|
||||
\.sys$
|
||||
\.tar$
|
||||
\.tgz$
|
||||
\.tiff?$
|
||||
\.ttf$
|
||||
\.vcxproj\.filters$
|
||||
\.vsdx$
|
||||
\.wav$
|
||||
\.webm$
|
||||
\.webp$
|
||||
\.woff
|
||||
\.woff2?$
|
||||
\.xcf$
|
||||
\.xls
|
||||
\.xlsx?$
|
||||
\.xpm$
|
||||
\.yml$
|
||||
\.xz$
|
||||
\.zip$
|
||||
^\.github/actions/spelling/
|
||||
^\.github/fabricbot.json$
|
||||
^\.gitignore$
|
||||
^\Q.git-blame-ignore-revs\E$
|
||||
^\Q.github/workflows/spelling.yml\E$
|
||||
^\Qdoc/reference/windows-terminal-logo.ans\E$
|
||||
^\Qsamples/ConPTY/EchoCon/EchoCon/EchoCon.vcxproj.filters\E$
|
||||
^\Qsrc/host/exe/Host.EXE.vcxproj.filters\E$
|
||||
^\Qbuild/config/release.gdnbaselines\E$
|
||||
^\Qsrc/host/ft_host/chafa.txt\E$
|
||||
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
|
||||
^\XamlStyler.json$
|
||||
^\Qsrc/host/ft_uia/run.bat\E$
|
||||
^\Qsrc/host/runft.bat\E$
|
||||
^\Qsrc/tools/lnkd/lnkd.bat\E$
|
||||
^\Qsrc/tools/pixels/pixels.bat\E$
|
||||
^build/config/
|
||||
^consolegit2gitfilters\.json$
|
||||
^dep/
|
||||
^doc/reference/master-sequence-list.csv$
|
||||
^doc/reference/master-sequence-list\.csv$
|
||||
^doc/reference/UTF8-torture-test\.txt$
|
||||
^doc/reference/windows-terminal-logo\.ans$
|
||||
^oss/
|
||||
^src/host/ft_uia/run\.bat$
|
||||
^src/host/runft\.bat$
|
||||
^src/host/runut\.bat$
|
||||
^samples/PixelShaders/Screenshots/
|
||||
^src/interactivity/onecore/BgfxEngine\.
|
||||
^src/renderer/atlas/
|
||||
^src/renderer/wddmcon/WddmConRenderer\.
|
||||
@@ -107,14 +115,13 @@
|
||||
^src/terminal/parser/ut_parser/Base64Test.cpp$
|
||||
^src/terminal/parser/ut_parser/run\.bat$
|
||||
^src/tools/benchcat
|
||||
^src/tools/integrity/dirs$
|
||||
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
|
||||
^src/tools/lnkd/lnkd\.bat$
|
||||
^src/tools/pixels/pixels\.bat$
|
||||
^src/tools/RenderingTests/main.cpp$
|
||||
^src/tools/RenderingTests/main\.cpp$
|
||||
^src/tools/texttests/fira\.txt$
|
||||
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
|
||||
^src/types/ColorFix.cpp
|
||||
^src/types/ut_types/UtilsTests.cpp$
|
||||
^tools/ReleaseEngineering/ServicingPipeline.ps1$
|
||||
^src/tools/U8U16Test/(?!en)..\.
|
||||
^src/types/ColorFix\.cpp$
|
||||
^src/types/ut_types/UtilsTests\.cpp$
|
||||
^tools/ReleaseEngineering/ServicingPipeline\.ps1$
|
||||
^XamlStyler\.json$
|
||||
ignore$
|
||||
SUMS$
|
||||
|
||||
5
.github/actions/spelling/expect/04cdb9b77d6827c0202f51acd4205b017015bfff.txt
vendored
Normal file
5
.github/actions/spelling/expect/04cdb9b77d6827c0202f51acd4205b017015bfff.txt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
EOB
|
||||
swrapped
|
||||
wordi
|
||||
wordiswrapped
|
||||
wrappe
|
||||
257
.github/actions/spelling/expect/expect.txt
vendored
257
.github/actions/spelling/expect/expect.txt
vendored
File diff suppressed because it is too large
Load Diff
2
.github/actions/spelling/expect/web.txt
vendored
2
.github/actions/spelling/expect/web.txt
vendored
@@ -1,6 +1,6 @@
|
||||
WCAG
|
||||
winui
|
||||
appshellintegration
|
||||
mdtauk
|
||||
gfycat
|
||||
Guake
|
||||
xkcd
|
||||
|
||||
73
.github/actions/spelling/line_forbidden.patterns
vendored
73
.github/actions/spelling/line_forbidden.patterns
vendored
@@ -1,4 +1,6 @@
|
||||
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
|
||||
# reject `m_data` as VxWorks defined it and that breaks things if it's used elsewhere
|
||||
# see [fprime](https://github.com/nasa/fprime/commit/d589f0a25c59ea9a800d851ea84c2f5df02fb529)
|
||||
# and [Qt](https://github.com/qtproject/qt-solutions/blame/fb7bc42bfcc578ff3fa3b9ca21a41e96eb37c1c7/qtscriptclassic/src/qscriptbuffer_p.h#L46)
|
||||
# \bm_data\b
|
||||
|
||||
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
|
||||
@@ -6,40 +8,72 @@
|
||||
# to use this:
|
||||
#\bfit\(
|
||||
|
||||
# s.b. anymore
|
||||
\bany more[,.]
|
||||
|
||||
# s.b. GitHub
|
||||
\bGithub\b
|
||||
(?<![&*.]|// |\btype )\bGithub\b(?![{)])
|
||||
|
||||
# s.b. GitLab
|
||||
\bGitlab\b
|
||||
(?<![&*.]|// |\btype )\bGitlab\b(?![{)])
|
||||
|
||||
# s.b. JavaScript
|
||||
\bJavascript\b
|
||||
|
||||
# s.b. macOS or Mac OS X or ...
|
||||
\bMacOS\b
|
||||
|
||||
# s.b. Microsoft
|
||||
\bMicroSoft\b
|
||||
|
||||
# s.b. TypeScript
|
||||
\bTypescript\b
|
||||
|
||||
# s.b. another
|
||||
\ban[- ]other\b
|
||||
|
||||
# s.b. deprecation warning
|
||||
\b[Dd]epreciation [Ww]arnings?\b
|
||||
|
||||
# s.b. greater than
|
||||
\bgreater then\b
|
||||
|
||||
# s.b. in front of
|
||||
\bin from of\b
|
||||
|
||||
# s.b. into
|
||||
#\sin to\s
|
||||
# when not phrasal and when `in order to` would be wrong:
|
||||
# https://thewritepractice.com/into-vs-in-to/
|
||||
#\sin to\s(?!if\b)
|
||||
|
||||
# s.b. is obsolete
|
||||
\bis obsolescent\b
|
||||
|
||||
# s.b. it's or its
|
||||
\bits['’]
|
||||
|
||||
# s.b. opt-in
|
||||
\sopt in\s
|
||||
#(?<!\sfor)\sopt in\s
|
||||
|
||||
# s.b. less than
|
||||
\bless then\b
|
||||
|
||||
# s.b. one of
|
||||
\bon of\b
|
||||
|
||||
# s.b. otherwise
|
||||
\bother[- ]wise\b
|
||||
|
||||
# s.b. or (more|less)
|
||||
\bore (?:more|less)\b
|
||||
|
||||
# s.b. nonexistent
|
||||
\bnon existing\b
|
||||
\b[Nn]o[nt][- ]existent\b
|
||||
|
||||
# s.b. brief / details/ param / return / retval
|
||||
(?:^\s*|(?:\*|//|/*)\s+`)[\\@](?:breif|(?:detail|detials)|(?:params(?!\.)|prama?)|ret(?:uns?)|retvl)\b
|
||||
|
||||
# s.b. preexisting
|
||||
[Pp]re[- ]existing
|
||||
|
||||
@@ -49,14 +83,37 @@
|
||||
# s.b. preemptively
|
||||
[Pp]re[- ]emptively
|
||||
|
||||
# s.b. recently changed or recent changes
|
||||
[Rr]ecent changed
|
||||
|
||||
# s.b. reentrancy
|
||||
[Rr]e[- ]entrancy
|
||||
|
||||
# s.b. reentrant
|
||||
[Rr]e[- ]entrant
|
||||
|
||||
# s.b. workaround(s)
|
||||
#\bwork[- ]arounds?\b
|
||||
# s.b. understand
|
||||
\bunder stand\b
|
||||
|
||||
# Reject duplicate words
|
||||
# s.b. workarounds
|
||||
#\bwork[- ]arounds\b
|
||||
|
||||
# s.b. workaround
|
||||
(?:(?:[Aa]|[Tt]he|ugly)\swork[- ]around\b|\swork[- ]around\s+for)
|
||||
|
||||
# s.b. (coarse|fine)-grained
|
||||
\b(?:coarse|fine) grained\b
|
||||
|
||||
# s.b. neither/nor -- or reword
|
||||
#\bnot\b[^.?!"/(]+\bnor\b
|
||||
|
||||
# probably a double negative
|
||||
# s.b. neither/nor (plus rewording the beginning)
|
||||
\bnot\b[^.?!"/]*\bneither\b[^.?!"/(]*\bnor\b
|
||||
|
||||
# In English, it is generally wrong to have the same word twice in a row without punctuation.
|
||||
# Duplicated words are generally mistakes.
|
||||
# There are a few exceptions where it is acceptable (e.g. "that that").
|
||||
# If the highlighted doubled word pair is in a code snippet, you can write a pattern to mask it.
|
||||
# If the highlighted doubled word pair is in prose, have someone read the English before you dismiss this error.
|
||||
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s
|
||||
|
||||
2
.github/actions/spelling/patterns/0_n.txt
vendored
2
.github/actions/spelling/patterns/0_n.txt
vendored
@@ -1,2 +0,0 @@
|
||||
\\native(?![a-z])
|
||||
\\nihilist(?![a-z])
|
||||
8
.github/actions/spelling/patterns/0_r.txt
vendored
8
.github/actions/spelling/patterns/0_r.txt
vendored
@@ -1,8 +0,0 @@
|
||||
\\registry(?![a-z])
|
||||
\\release(?![a-z])
|
||||
\\resources?(?![a-z])
|
||||
\\result(?![a-z])
|
||||
\\resultmacros(?![a-z])
|
||||
\\rules(?![a-z])
|
||||
\\renderer(?![a-z])
|
||||
\\rectread(?![a-z])
|
||||
13
.github/actions/spelling/patterns/0_t.txt
vendored
13
.github/actions/spelling/patterns/0_t.txt
vendored
@@ -1,13 +0,0 @@
|
||||
\\telemetry(?![a-z])
|
||||
\\templates(?![a-z])
|
||||
\\term(?![a-z])
|
||||
\\terminal(?![a-z])
|
||||
\\terminalcore(?![a-z])
|
||||
\\terminalinput(?![a-z])
|
||||
\\testlist(?![a-z])
|
||||
\\testmd(?![a-z])
|
||||
\\testpasses(?![a-z])
|
||||
\\tests(?![a-z])
|
||||
\\thread(?![a-z])
|
||||
\\tools(?![a-z])
|
||||
\\types?(?![a-z])
|
||||
4
.github/actions/spelling/patterns/README.md
vendored
4
.github/actions/spelling/patterns/README.md
vendored
@@ -7,10 +7,6 @@ Note: order of the contents of these files can matter.
|
||||
Lines from an individual file are handled in file order.
|
||||
Files are selected in alphabetical order.
|
||||
|
||||
* [n](0_n.txt), [r](0_r.txt), and [t](0_t.txt) are specifically to work around
|
||||
a quirk in the spell checker:
|
||||
it often sees C strings of the form "Hello\nwerld". And would prefer to
|
||||
spot the typo of `werld`.
|
||||
* [patterns](patterns.txt) is the main list -- there is nothing
|
||||
particularly special about the file name (beyond the extension which is
|
||||
important).
|
||||
|
||||
132
.github/actions/spelling/patterns/patterns.txt
vendored
132
.github/actions/spelling/patterns/patterns.txt
vendored
@@ -3,7 +3,7 @@
|
||||
https?://\S+
|
||||
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
|
||||
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
|
||||
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]{0,2}\b
|
||||
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}(?!\[)[Uu]?[Ll]{0,2}\b
|
||||
microsoft/cascadia-code\@[0-9a-fA-F]{40}
|
||||
\d+x\d+Logo
|
||||
Scro\&ll
|
||||
@@ -12,7 +12,6 @@ Scro\&ll
|
||||
TestUtils::VerifyExpectedString\(tb, L"[^"]+"
|
||||
(?:hostSm|mach)\.ProcessString\(L"[^"]+"
|
||||
\b([A-Za-z])\g{-1}{3,}\b
|
||||
0x[0-9A-Za-z]+
|
||||
Base64::s_(?:En|De)code\(L"[^"]+"
|
||||
VERIFY_ARE_EQUAL\(L"[^"]+"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"
|
||||
@@ -24,70 +23,129 @@ ROY\sG\.\sBIV
|
||||
!(?:(?i)ESC)!\[
|
||||
!(?:(?i)CSI)!(?:\d+(?:;\d+|)m|[ABCDF])
|
||||
|
||||
# Python stringprefix / binaryprefix
|
||||
\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'
|
||||
|
||||
# SSE intrinsics like "_mm_subs_epu16"
|
||||
\b_mm(?:|256|512)_\w+\b
|
||||
|
||||
# ARM NEON intrinsics like "vsubq_u16"
|
||||
\bv\w+_[fsu](?:8|16|32|64)\b
|
||||
|
||||
# color floating numbers
|
||||
0x[0-9a-f](?:\.[0-9a-f]*p)[-+]\d+f
|
||||
|
||||
# AppX package
|
||||
_\d[0-9a-z]{12}['\.]
|
||||
|
||||
# string test
|
||||
equals_insensitive_ascii\("\w+", "\w+"
|
||||
|
||||
# Automatically suggested patterns
|
||||
# hit-count: 3831 file-count: 582
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
# hit-count: 3788 file-count: 599
|
||||
# IServiceProvider / isAThing
|
||||
\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
|
||||
# hit-count: 71 file-count: 35
|
||||
# Compiler flags
|
||||
(?:^|[\t ,"'`=(])-[D](?=[A-Z]{2,}|[A-Z][a-z])
|
||||
(?:^|[\t ,"'`=(])-[X](?!aml)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# hit-count: 41 file-count: 28
|
||||
# version suffix <word>v#
|
||||
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
|
||||
|
||||
# hit-count: 20 file-count: 9
|
||||
# hit-count: 314 file-count: 21
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
|
||||
# hit-count: 10 file-count: 7
|
||||
# hit-count: 47 file-count: 11
|
||||
# special cased printf markers
|
||||
\\r\\n(?=[a-z])|(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*(?:<.*['"`]|"(?:[;,]|\);)$|\) \+$))
|
||||
|
||||
# ConsoleArgumentsTests
|
||||
--headless\\.*?"
|
||||
|
||||
# hit-count: 109 file-count: 62
|
||||
# Compiler flags (Unix, Java/Scala)
|
||||
# Use if you have things like `-Pdocker` and want to treat them as `docker`
|
||||
(?:^|[\t ,>"'`=(])-(?:D(?=[A-Z])|[WX]|f(?=[ms]))(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# hit-count: 60 file-count: 35
|
||||
# version suffix <word>v#
|
||||
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
|
||||
|
||||
# hit-count: 2 file-count: 2
|
||||
# This does not cover multiline strings, if your repository has them,
|
||||
# you'll want to remove the `(?=.*?")` suffix.
|
||||
# The `(?=.*?")` suffix should limit the false positives rate
|
||||
# printf
|
||||
%(?:s)(?!ize)(?=[a-z]{2,})
|
||||
|
||||
# hit-count: 16 file-count: 10
|
||||
# uuid:
|
||||
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
|
||||
|
||||
# hit-count: 13 file-count: 4
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
|
||||
|
||||
# hit-count: 7 file-count: 5
|
||||
# hex digits including css/html color classes:
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
|
||||
|
||||
# hit-count: 7 file-count: 1
|
||||
# regex choice
|
||||
\(\?:[^)]+\|[^)]+\)
|
||||
|
||||
# hit-count: 4 file-count: 4
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
# tar arguments
|
||||
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
|
||||
|
||||
# hit-count: 4 file-count: 1
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
|
||||
|
||||
# hit-count: 4 file-count: 1
|
||||
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
|
||||
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
|
||||
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
|
||||
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
|
||||
## You could manually change `(?i)X...` to use `[Xx]...`
|
||||
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
|
||||
# Lorem
|
||||
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
|
||||
|
||||
# hit-count: 3 file-count: 3
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
# hit-count: 2 file-count: 1
|
||||
# latex
|
||||
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
# Python string prefix / binary prefix
|
||||
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
|
||||
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?=[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# hex digits including css/html color classes:
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
|
||||
# Punycode
|
||||
\bxn--[-0-9a-z]+
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
|
||||
# latex (check-spelling >= 0.0.22)
|
||||
\\\w{2,}\{
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# French
|
||||
# This corpus only had capital letters, but you probably want lowercase ones as well.
|
||||
\b[LN]'+[a-z]{2,}\b
|
||||
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
|
||||
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
|
||||
|
||||
# Questionably acceptable forms of `in to`
|
||||
# Personally, I prefer `log into`, but people object
|
||||
# https://www.tprteaching.com/log-into-log-in-to-login/
|
||||
\b(?:[Ll]og|[Ss]ign) in to\b
|
||||
|
||||
# to opt in
|
||||
\bto opt in\b
|
||||
|
||||
# acceptable duplicates
|
||||
# ls directory listings
|
||||
[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+
|
||||
# C/idl types + English ...
|
||||
\s(Guid|long|LONG|that) \g{-1}\s
|
||||
|
||||
# javadoc / .net
|
||||
(?:[\\@](?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s
|
||||
[-bcdlpsw](?:[-r][-w][-Ssx]){3}\s+\d+\s+\S+\s+\S+\s+\d+\s+
|
||||
# mount
|
||||
\bmount\s+-t\s+(\w+)\s+\g{-1}\b
|
||||
# C types and repeated CSS values
|
||||
\s(auto|center|div|Guid|inherit|long|LONG|none|normal|solid|that|thin|transparent|very)(?: \g{-1})+\s
|
||||
# C struct
|
||||
\bstruct\s+(\w+)\s+\g{-1}\b
|
||||
# go templates
|
||||
\s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml):
|
||||
# doxygen / javadoc / .net
|
||||
(?:[\\@](?:brief|groupname|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+static|\s+override|\s+readonly)*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s
|
||||
|
||||
# Commit message -- Signed-off-by and friends
|
||||
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$
|
||||
|
||||
1
.github/actions/spelling/reject.txt
vendored
1
.github/actions/spelling/reject.txt
vendored
@@ -1,6 +1,7 @@
|
||||
^attache$
|
||||
^attacher$
|
||||
^attachers$
|
||||
^bellow$
|
||||
benefitting
|
||||
occurences?
|
||||
^dependan.*
|
||||
|
||||
4
.github/workflows/addToProject.yml
vendored
4
.github/workflows/addToProject.yml
vendored
@@ -7,13 +7,13 @@ on:
|
||||
- labeled
|
||||
- unlabeled
|
||||
|
||||
permissions: {}
|
||||
permissions: {}
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v0.3.0
|
||||
- uses: actions/add-to-project@v0.5.0
|
||||
with:
|
||||
project-url: https://github.com/orgs/microsoft/projects/159
|
||||
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
|
||||
|
||||
32
.github/workflows/similarIssues.yml
vendored
Normal file
32
.github/workflows/similarIssues.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: GitGudSimilarIssues comments
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
getSimilarIssues:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
message: ${{ steps.getBody.outputs.message }}
|
||||
steps:
|
||||
- id: getBody
|
||||
uses: craigloewen-msft/GitGudSimilarIssues@main
|
||||
with:
|
||||
issuetitle: ${{ github.event.issue.title }}
|
||||
repo: ${{ github.repository }}
|
||||
similaritytolerance: "0.75"
|
||||
add-comment:
|
||||
needs: getSimilarIssues
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
if: needs.getSimilarIssues.outputs.message != ''
|
||||
steps:
|
||||
- name: Add comment
|
||||
run: gh issue comment "$NUMBER" --repo "$REPO" --body "$BODY"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NUMBER: ${{ github.event.issue.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
BODY: ${{ needs.getSimilarIssues.outputs.message }}
|
||||
115
.github/workflows/spelling2.yml
vendored
115
.github/workflows/spelling2.yml
vendored
@@ -5,7 +5,7 @@ name: Spell checking
|
||||
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
|
||||
#
|
||||
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
|
||||
# (in odd cases, it might actually run just to collapse a commment, but that's fairly rare)
|
||||
# (in odd cases, it might actually run just to collapse a comment, but that's fairly rare)
|
||||
# it needs `contents: write` in order to add a comment.
|
||||
#
|
||||
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
|
||||
@@ -34,6 +34,29 @@ name: Spell checking
|
||||
#
|
||||
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
|
||||
|
||||
# Sarif reporting
|
||||
#
|
||||
# Access to Sarif reports is generally restricted (by GitHub) to members of the repository.
|
||||
#
|
||||
# Requires enabling `security-events: write`
|
||||
# and configuring the action with `use_sarif: 1`
|
||||
#
|
||||
# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Sarif-output
|
||||
|
||||
# Minimal workflow structure:
|
||||
#
|
||||
# on:
|
||||
# push:
|
||||
# ...
|
||||
# pull_request_target:
|
||||
# ...
|
||||
# jobs:
|
||||
# # you only want the spelling job, all others should be omitted
|
||||
# spelling:
|
||||
# # remove `security-events: write` and `use_sarif: 1`
|
||||
# # remove `experimental_apply_changes_via_bot: 1`
|
||||
# ... otherwise adjust the `with:` as you wish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -43,8 +66,6 @@ on:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
types:
|
||||
- 'opened'
|
||||
- 'reopened'
|
||||
@@ -60,10 +81,11 @@ jobs:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
actions: read
|
||||
security-events: write
|
||||
outputs:
|
||||
followup: ${{ steps.spelling.outputs.followup }}
|
||||
runs-on: ubuntu-latest
|
||||
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'"
|
||||
if: ${{ contains(github.event_name, 'pull_request') || github.event_name == 'push' }}
|
||||
concurrency:
|
||||
group: spelling-${{ github.event.pull_request.number || github.ref }}
|
||||
# note: If you use only_check_changed_files, you do not want cancel-in-progress
|
||||
@@ -71,35 +93,50 @@ jobs:
|
||||
steps:
|
||||
- name: check-spelling
|
||||
id: spelling
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
uses: check-spelling/check-spelling@v0.0.22
|
||||
with:
|
||||
suppress_push_for_open_pull_request: 1
|
||||
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
|
||||
checkout: true
|
||||
check_file_names: 1
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
spell_check_this: microsoft/terminal@main
|
||||
post_comment: 0
|
||||
use_magic_file: 1
|
||||
extra_dictionary_limit: 10
|
||||
report-timing: 1
|
||||
warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check
|
||||
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
|
||||
use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }}
|
||||
extra_dictionary_limit: 20
|
||||
extra_dictionaries:
|
||||
cspell:software-terms/src/software-terms.txt
|
||||
cspell:python/src/python/python-lib.txt
|
||||
cspell:node/node.txt
|
||||
cspell:cpp/src/stdlib-c.txt
|
||||
cspell:software-terms/dict/softwareTerms.txt
|
||||
cspell:cpp/src/stdlib-cpp.txt
|
||||
cspell:fullstack/fullstack.txt
|
||||
cspell:lorem-ipsum/dictionary.txt
|
||||
cspell:cpp/src/stdlib-c.txt
|
||||
cspell:php/dict/php.txt
|
||||
cspell:filetypes/filetypes.txt
|
||||
cspell:html/html.txt
|
||||
cspell:cpp/src/compiler-msvc.txt
|
||||
cspell:java/src/java.txt
|
||||
cspell:python/src/common/extra.txt
|
||||
cspell:powershell/powershell.txt
|
||||
cspell:node/dict/node.txt
|
||||
cspell:java/src/java-terms.txt
|
||||
cspell:aws/aws.txt
|
||||
cspell:cpp/src/lang-keywords.txt
|
||||
cspell:npm/npm.txt
|
||||
cspell:dotnet/dotnet.txt
|
||||
cspell:python/src/python/python.txt
|
||||
cspell:css/css.txt
|
||||
cspell:typescript/dict/typescript.txt
|
||||
cspell:dotnet/dict/dotnet.txt
|
||||
cspell:golang/dict/go.txt
|
||||
cspell:fullstack/dict/fullstack.txt
|
||||
cspell:cpp/src/compiler-msvc.txt
|
||||
cspell:python/src/python/python-lib.txt
|
||||
cspell:mnemonics/src/mnemonics.txt
|
||||
cspell:cpp/src/stdlib-cmath.txt
|
||||
check_extra_dictionaries: ''
|
||||
cspell:css/dict/css.txt
|
||||
cspell:cpp/src/lang-keywords.txt
|
||||
cspell:django/dict/django.txt
|
||||
cspell:python/src/python/python.txt
|
||||
cspell:html/dict/html.txt
|
||||
cspell:cpp/src/ecosystem.txt
|
||||
cspell:cpp/src/compiler-clang-attributes.txt
|
||||
cspell:npm/dict/npm.txt
|
||||
cspell:r/src/r.txt
|
||||
cspell:powershell/dict/powershell.txt
|
||||
cspell:csharp/csharp.txt
|
||||
|
||||
comment-push:
|
||||
name: Report (Push)
|
||||
@@ -111,10 +148,10 @@ jobs:
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
uses: check-spelling/check-spelling@v0.0.22
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
spell_check_this: microsoft/terminal@main
|
||||
task: ${{ needs.spelling.outputs.followup }}
|
||||
|
||||
comment-pr:
|
||||
@@ -123,12 +160,38 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: spelling
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
uses: check-spelling/check-spelling@v0.0.22
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
spell_check_this: microsoft/terminal@main
|
||||
task: ${{ needs.spelling.outputs.followup }}
|
||||
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
|
||||
|
||||
update:
|
||||
name: Update PR
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: read
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{
|
||||
github.repository_owner != 'microsoft' &&
|
||||
github.event_name == 'issue_comment' &&
|
||||
github.event.issue.pull_request &&
|
||||
contains(github.event.comment.body, '@check-spelling-bot apply')
|
||||
}}
|
||||
concurrency:
|
||||
group: spelling-update-${{ github.event.issue.number }}
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- name: apply spelling updates
|
||||
uses: check-spelling/check-spelling@v0.0.22
|
||||
with:
|
||||
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
|
||||
checkout: true
|
||||
ssh_key: "${{ secrets.CHECK_SPELLING }}"
|
||||
|
||||
@@ -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/main/doc/bot.md) to help us automate common processes within our workflow.
|
||||
We employ [a bot engine](./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.
|
||||
|
||||
|
||||
@@ -239,8 +239,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{89CDCC
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types.Unit.Tests", "src\types\ut_types\Types.Unit.Tests.vcxproj", "{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PublicTerminalCore", "src\cascadia\PublicTerminalCore\PublicTerminalCore.vcxproj", "{84848BFA-931D-42CE-9ADF-01EE54DE7890}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalControl", "src\cascadia\WpfTerminalControl\WpfTerminalControl.csproj", "{376FE273-6B84-4EB5-8B30-8DE9D21B022C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}"
|
||||
@@ -334,7 +332,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxp
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "src\cascadia\WpfTerminalTestNetCore\WpfTerminalTestNetCore.csproj", "{1588FD7C-241E-4E7D-9113-43735F3E6BAD}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890} = {84848BFA-931D-42CE-9ADF-01EE54DE7890}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{A22EC5F6-7851-4B88-AC52-47249D437A52} = {A22EC5F6-7851-4B88-AC52-47249D437A52}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@@ -1711,34 +1709,6 @@ Global
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}.Release|x64.Build.0 = Release|x64
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}.Release|x86.ActiveCfg = Release|Win32
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}.Release|x86.Build.0 = Release|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|x64.Build.0 = AuditMode|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|x64.Build.0 = Debug|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|x86.Build.0 = Debug|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|x64.ActiveCfg = Release|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|x64.Build.0 = Release|x64
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|x86.ActiveCfg = Release|Win32
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|x86.Build.0 = Release|Win32
|
||||
{376FE273-6B84-4EB5-8B30-8DE9D21B022C}.AuditMode|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{376FE273-6B84-4EB5-8B30-8DE9D21B022C}.AuditMode|ARM.ActiveCfg = Debug|Any CPU
|
||||
{376FE273-6B84-4EB5-8B30-8DE9D21B022C}.AuditMode|ARM.Build.0 = Debug|Any CPU
|
||||
@@ -2894,7 +2864,6 @@ Global
|
||||
{05500DEF-2294-41E3-AF9A-24E580B82836} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
{1E4A062E-293B-4817-B20D-BF16B979E350} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890} = {4DAF0299-495E-4CD1-A982-9BAC16A45932}
|
||||
{376FE273-6B84-4EB5-8B30-8DE9D21B022C} = {4DAF0299-495E-4CD1-A982-9BAC16A45932}
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
|
||||
50
README.md
50
README.md
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Welcome to the Windows Terminal, Console and Command-Line repo
|
||||
|
||||
@@ -8,8 +8,8 @@ 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/main/src/tools/ColorTool)
|
||||
* [Sample projects](https://github.com/microsoft/terminal/tree/main/samples)
|
||||
* [ColorTool](./src/tools/ColorTool)
|
||||
* [Sample projects](./samples)
|
||||
that show how to consume the Windows Console APIs
|
||||
|
||||
Related repositories include:
|
||||
@@ -21,7 +21,7 @@ Related repositories include:
|
||||
|
||||
## Installing and running Windows Terminal
|
||||
|
||||
> **Note**\
|
||||
> [!NOTE]
|
||||
> Windows Terminal requires Windows 10 2004 (build 19041) or later
|
||||
|
||||
### Microsoft Store [Recommended]
|
||||
@@ -53,7 +53,7 @@ fails for any reason, you can try the following command at a PowerShell prompt:
|
||||
Add-AppxPackage Microsoft.WindowsTerminal_<versionNumber>.msixbundle
|
||||
```
|
||||
|
||||
> **Note**\
|
||||
> [!NOTE]
|
||||
> If you install Terminal manually:
|
||||
>
|
||||
> * You may need to install the [VC++ v14 Desktop Framework Package](https://docs.microsoft.com/troubleshoot/cpp/c-runtime-packages-desktop-bridge#how-to-install-and-update-desktop-framework-packages).
|
||||
@@ -72,8 +72,8 @@ package:
|
||||
winget install --id Microsoft.WindowsTerminal -e
|
||||
```
|
||||
|
||||
> **Note**\
|
||||
> Due to [a dependency issue](https://github.com/microsoft/terminal/issues/15663), Terminal's current versions cannot be installed via the Windows Package Manager CLI. To install the stable release 1.17 or later, or the Preview release 1.18 or later, please use an alternative installation method.
|
||||
> [!NOTE]
|
||||
> Dependency support is available in WinGet version [1.6.2631 or later](https://github.com/microsoft/winget-cli/releases). To install the Terminal stable release 1.18 or later, please make sure you have the updated version of the WinGet client.
|
||||
|
||||
#### Via Chocolatey (unofficial)
|
||||
|
||||
@@ -118,9 +118,31 @@ repository.
|
||||
|
||||
---
|
||||
|
||||
## Installing Windows Terminal Canary
|
||||
Windows Terminal Canary is a nightly build of Windows Terminal. This build has the latest code from our `main` branch, giving you an opportunity to try features before they make it to Windows Terminal Preview.
|
||||
|
||||
Windows Terminal Canary is our least stable offering, so you may discover bugs before we have had a chance to find them.
|
||||
|
||||
Windows Terminal Canary is available as an App Installer distribution and a Portable ZIP distribution.
|
||||
|
||||
The App Installer distribution supports automatic updates. Due to platform limitations, this installer only works on Windows 11.
|
||||
|
||||
The Portable ZIP distribution is a portable application. It will not automatically update and will not automatically check for updates. This portable ZIP distribution works on Windows 10 (19041+) and Windows 11.
|
||||
|
||||
| Distribution | Architecture | Link |
|
||||
|---------------|:---------------:|------------------------------------------------------|
|
||||
| App Installer | x64, arm64, x86 | [download](https://aka.ms/terminal-canary-installer) |
|
||||
| Portable ZIP | x64 | [download](https://aka.ms/terminal-canary-zip-x64) |
|
||||
| Portable ZIP | ARM64 | [download](https://aka.ms/terminal-canary-zip-arm64) |
|
||||
| Portable ZIP | x86 | [download](https://aka.ms/terminal-canary-zip-x86) |
|
||||
|
||||
_Learn more about the [types of Windows Terminal distributions](https://learn.microsoft.com/windows/terminal/distributions)._
|
||||
|
||||
---
|
||||
|
||||
## Windows Terminal Roadmap
|
||||
|
||||
The plan for the Windows Terminal [is described here](/doc/roadmap-2022.md) and
|
||||
The plan for the Windows Terminal [is described here](/doc/roadmap-2023.md) and
|
||||
will be updated as the project proceeds.
|
||||
|
||||
## Project Build Status
|
||||
@@ -240,7 +262,7 @@ Cause: You're launching the incorrect solution in Visual Studio.
|
||||
Solution: Make sure you're building & deploying the `CascadiaPackage` project in
|
||||
Visual Studio.
|
||||
|
||||
> **Note**\
|
||||
> [!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
|
||||
@@ -264,7 +286,7 @@ enhance Windows Terminal\!
|
||||
|
||||
***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
|
||||
Guide](./CONTRIBUTING.md) to
|
||||
help avoid any wasted or duplicate effort.
|
||||
|
||||
## Communicating with the Team
|
||||
@@ -365,10 +387,10 @@ Please review these brief docs below about our coding practices.
|
||||
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/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)
|
||||
* [Coding Style](./doc/STYLE.md)
|
||||
* [Code Organization](./doc/ORGANIZATION.md)
|
||||
* [Exceptions in our legacy codebase](./doc/EXCEPTIONS.md)
|
||||
* [Helpful smart pointers and macros for interfacing with Windows in WIL](./doc/WIL.md)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -14,4 +14,4 @@ Support for Windows Terminal is limited to the resources listed above.
|
||||
[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
|
||||
[contributor]: ./CONTRIBUTING.md
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"MatchedPath": [
|
||||
"PublicTerminalCore.dll"
|
||||
"Microsoft.Terminal.Control/Microsoft.Terminal.Control.dll"
|
||||
],
|
||||
"SigningInfo": {
|
||||
"Operations": [
|
||||
|
||||
1127
build/config/release.gdnbaselines
Normal file
1127
build/config/release.gdnbaselines
Normal file
File diff suppressed because it is too large
Load Diff
38
build/config/template.appinstaller
Normal file
38
build/config/template.appinstaller
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AppInstaller
|
||||
xmlns="http://schemas.microsoft.com/appx/appinstaller/2017/2"
|
||||
Version="1.0.0.0"
|
||||
Uri="$$ROOT$$$$NAME$$.appinstaller">
|
||||
|
||||
<MainBundle
|
||||
Name="$$NAME$$"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="$$VERSION$$"
|
||||
Uri="$$ROOT$$$$PACKAGE$$" />
|
||||
|
||||
<Dependencies>
|
||||
<Package
|
||||
Name="Microsoft.UI.Xaml.2.8"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="8.2305.5001.0"
|
||||
ProcessorArchitecture="x64"
|
||||
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.x64.appx" />
|
||||
<Package
|
||||
Name="Microsoft.UI.Xaml.2.8"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="8.2305.5001.0"
|
||||
ProcessorArchitecture="x86"
|
||||
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.x86.appx" />
|
||||
<Package
|
||||
Name="Microsoft.UI.Xaml.2.8"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="8.2305.5001.0"
|
||||
ProcessorArchitecture="arm64"
|
||||
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.arm64.appx" />
|
||||
</Dependencies>
|
||||
|
||||
<UpdateSettings>
|
||||
<OnLaunch
|
||||
HoursBetweenUpdateChecks="6" />
|
||||
</UpdateSettings>
|
||||
</AppInstaller>
|
||||
6
build/config/tsa.json
Normal file
6
build/config/tsa.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"instanceUrl": "https://microsoft.visualstudio.com",
|
||||
"projectName": "OS",
|
||||
"areaPath": "OS\\Windows Client and Services\\ADEPT\\E4D-Engineered for Developers\\SHINE\\Terminal",
|
||||
"notificationAliases": ["condev@microsoft.com", "duhowett@microsoft.com"]
|
||||
}
|
||||
@@ -102,7 +102,7 @@ stages:
|
||||
|
||||
- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
|
||||
- stage: CodeIndexer
|
||||
displayName: Github CodeNav Indexer
|
||||
displayName: GitHub CodeNav Indexer
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./templates-v2/job-index-github-codenav.yml
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
trigger: none
|
||||
pr: none
|
||||
schedules:
|
||||
- cron: "30 3 * * 2-6" # Run at 03:30 UTC Tuesday through Saturday (After the work day in Pacific, Mon-Fri)
|
||||
displayName: "Nightly Terminal Build"
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: false # only run if there's code changes!
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
extends:
|
||||
template: templates-v2\pipeline-full-release-build.yml
|
||||
parameters:
|
||||
branding: Canary
|
||||
buildTerminal: true
|
||||
pgoBuildMode: Optimize
|
||||
codeSign: true
|
||||
generateSbom: true
|
||||
publishSymbolsToPublic: true
|
||||
publishVpackToWindows: false
|
||||
symbolExpiryTime: 15 # Nightly builds do not keep symbols for very long!
|
||||
53
build/pipelines/ob-nightly.yml
Normal file
53
build/pipelines/ob-nightly.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
trigger: none
|
||||
pr: none
|
||||
schedules:
|
||||
- cron: "30 3 * * 2-6" # Run at 03:30 UTC Tuesday through Saturday (After the work day in Pacific, Mon-Fri)
|
||||
displayName: "Nightly Terminal Build"
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: false # only run if there's code changes!
|
||||
|
||||
parameters:
|
||||
- name: publishToAzure
|
||||
displayName: "Deploy to **PUBLIC** Azure Storage"
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
variables:
|
||||
- template: templates-v2/variables-nuget-package-version.yml
|
||||
parameters:
|
||||
branding: Canary
|
||||
- template: templates-v2/variables-onebranch-config.yml
|
||||
|
||||
extends:
|
||||
template: templates-v2/pipeline-onebranch-full-release-build.yml
|
||||
parameters:
|
||||
official: true
|
||||
branding: Canary
|
||||
buildTerminal: true
|
||||
pgoBuildMode: Optimize
|
||||
codeSign: true
|
||||
publishSymbolsToPublic: true
|
||||
publishVpackToWindows: false
|
||||
symbolExpiryTime: 15
|
||||
${{ if eq(true, parameters.publishToAzure) }}:
|
||||
extraPublishJobs:
|
||||
- template: build/pipelines/templates-v2/job-deploy-to-azure-storage.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: "$(Build.SourcesDirectory)/_none"
|
||||
dependsOn: [PublishSymbols]
|
||||
storagePublicRootURL: $(AppInstallerRootURL)
|
||||
subscription: $(AzureSubscriptionName)
|
||||
storageAccount: $(AzureStorageAccount)
|
||||
storageContainer: $(AzureStorageContainer)
|
||||
buildConfiguration: Release
|
||||
buildPlatforms: [x64, x86, arm64]
|
||||
environment: production-canary
|
||||
|
||||
@@ -44,14 +44,6 @@ parameters:
|
||||
- x64
|
||||
- x86
|
||||
- arm64
|
||||
- name: codeSign
|
||||
displayName: "Sign all build outputs"
|
||||
type: boolean
|
||||
default: true
|
||||
- name: generateSbom
|
||||
displayName: "Generate a Bill of Materials"
|
||||
type: boolean
|
||||
default: true
|
||||
- name: terminalInternalPackageVersion
|
||||
displayName: "Terminal Internal Package Version"
|
||||
type: string
|
||||
@@ -68,9 +60,16 @@ parameters:
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
variables:
|
||||
- template: templates-v2/variables-nuget-package-version.yml
|
||||
parameters:
|
||||
branding: ${{ parameters.branding }}
|
||||
- template: templates-v2/variables-onebranch-config.yml
|
||||
|
||||
extends:
|
||||
template: templates-v2/pipeline-full-release-build.yml
|
||||
template: templates-v2/pipeline-onebranch-full-release-build.yml
|
||||
parameters:
|
||||
official: true
|
||||
branding: ${{ parameters.branding }}
|
||||
buildTerminal: ${{ parameters.buildTerminal }}
|
||||
buildConPTY: ${{ parameters.buildConPTY }}
|
||||
@@ -78,8 +77,7 @@ extends:
|
||||
pgoBuildMode: ${{ parameters.pgoBuildMode }}
|
||||
buildConfigurations: ${{ parameters.buildConfigurations }}
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
codeSign: ${{ parameters.codeSign }}
|
||||
generateSbom: ${{ parameters.generateSbom }}
|
||||
codeSign: true
|
||||
terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }}
|
||||
publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }}
|
||||
publishVpackToWindows: ${{ parameters.publishVpackToWindows }}
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
flattenFolders: true
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
- task: EsrpCodeSigning@1
|
||||
- task: EsrpCodeSigning@3
|
||||
displayName: Submit *.nupkg to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
|
||||
@@ -62,6 +62,9 @@ parameters:
|
||||
- name: publishArtifacts
|
||||
type: boolean
|
||||
default: true
|
||||
- name: removeAllNonSignedFiles
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.jobName }}
|
||||
@@ -89,6 +92,11 @@ jobs:
|
||||
# Yup.
|
||||
BuildTargetParameter: ' '
|
||||
SelectedSigningFragments: ' '
|
||||
# When building the unpackaged distribution, build it in portable mode if it's Canary-branded
|
||||
${{ if eq(parameters.branding, 'Canary') }}:
|
||||
UnpackagedBuildArguments: -PortableMode
|
||||
${{ else }}:
|
||||
UnpackagedBuildArguments: ' '
|
||||
JobOutputDirectory: $(Terminal.BinDir)
|
||||
JobOutputArtifactName: build-$(BuildPlatform)-$(BuildConfiguration)${{ parameters.artifactStem }}
|
||||
${{ insert }}: ${{ parameters.variables }}
|
||||
@@ -114,7 +122,7 @@ jobs:
|
||||
$SignFragments += "wpfdotnet"
|
||||
}
|
||||
If ([bool]::Parse("${{ parameters.buildWPF }}")) {
|
||||
$BuildTargets += "Terminal\wpf\PublicTerminalCore"
|
||||
$BuildTargets += "Terminal\Control\Microsoft_Terminal_Control"
|
||||
$SignFragments += "wpf"
|
||||
}
|
||||
If ([bool]::Parse("${{ parameters.buildConPTY }}")) {
|
||||
@@ -168,6 +176,7 @@ jobs:
|
||||
# - Directories ending in Lib (static lib projects that we fully linked into DLLs which may also contain unnecessary resources)
|
||||
# - All LocalTests_ project outputs, as they were subsumed into TestHostApp
|
||||
# - All PDB files inside the WindowsTerminal/ output, which do not belong there.
|
||||
# - console.dll, which apparently breaks XFGCheck? lol.
|
||||
- pwsh: |-
|
||||
$binDir = '$(Terminal.BinDir)'
|
||||
$ImportLibs = Get-ChildItem $binDir -Recurse -File -Filter '*.exp' | ForEach-Object { $_.FullName -Replace "exp$","lib" }
|
||||
@@ -184,6 +193,8 @@ jobs:
|
||||
$Items += Get-ChildItem '$(Terminal.BinDir)' -Filter '*.pdb' -Recurse
|
||||
}
|
||||
|
||||
$Items += Get-ChildItem $binDir -Filter 'console.dll'
|
||||
|
||||
$Items | Remove-Item -Recurse -Force -Verbose -ErrorAction:Ignore
|
||||
displayName: Clean up static libs and extra symbols
|
||||
errorActionPreference: silentlyContinue # It's OK if this silently fails
|
||||
@@ -224,7 +235,7 @@ jobs:
|
||||
|
||||
# Code-sign everything we just put together.
|
||||
# We run the signing in Terminal.BinDir, because all of the signing batches are relative to the final architecture/configuration output folder.
|
||||
- task: EsrpCodeSigning@1
|
||||
- task: EsrpCodeSigning@3
|
||||
displayName: Submit Signing Request
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
@@ -241,6 +252,14 @@ jobs:
|
||||
Write-Host "##vso[task.setvariable variable=WindowsTerminalPackagePath]${PackageFilename}"
|
||||
displayName: Re-pack the new Terminal package after signing
|
||||
|
||||
# Some of our governed pipelines explicitly fail builds that have *any* non-codesigned filed (!)
|
||||
- ${{ if eq(parameters.removeAllNonSignedFiles, true) }}:
|
||||
- pwsh: |-
|
||||
Get-ChildItem "$(Terminal.BinDir)" -Recurse -Include "*.dll","*.exe" |
|
||||
Where-Object { (Get-AuthenticodeSignature $_).Status -Ne "Valid" } |
|
||||
Remove-Item -Verbose -Force
|
||||
displayName: Remove all non-signed output files
|
||||
|
||||
- ${{ else }}: # No Signing
|
||||
- ${{ if or(parameters.buildTerminal, parameters.buildEverything) }}:
|
||||
- pwsh: |-
|
||||
@@ -255,7 +274,7 @@ jobs:
|
||||
- pwsh: |-
|
||||
$XamlAppxPath = (Get-Item "src\cascadia\CascadiaPackage\AppPackages\*\Dependencies\$(BuildPlatform)\Microsoft.UI.Xaml*.appx").FullName
|
||||
$outDir = New-Item -Type Directory "$(Terminal.BinDir)/_unpackaged" -ErrorAction:Ignore
|
||||
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination $outDir.FullName
|
||||
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 $(UnpackagedBuildArguments) -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination $outDir.FullName
|
||||
displayName: Build Unpackaged Distribution (from MSIX)
|
||||
condition: and(succeeded(), ne(variables.WindowsTerminalPackagePath, ''))
|
||||
|
||||
|
||||
92
build/pipelines/templates-v2/job-deploy-to-azure-storage.yml
Normal file
92
build/pipelines/templates-v2/job-deploy-to-azure-storage.yml
Normal file
@@ -0,0 +1,92 @@
|
||||
parameters:
|
||||
- name: buildConfiguration
|
||||
type: string
|
||||
- name: buildPlatforms
|
||||
type: object
|
||||
- name: pool
|
||||
type: object
|
||||
default: []
|
||||
- name: dependsOn
|
||||
type: object
|
||||
default: null
|
||||
- name: artifactStem
|
||||
type: string
|
||||
default: ''
|
||||
- name: variables
|
||||
type: object
|
||||
default: {}
|
||||
- name: environment
|
||||
type: string
|
||||
- name: storagePublicRootURL
|
||||
type: string
|
||||
- name: subscription
|
||||
type: string
|
||||
- name: storageAccount
|
||||
type: string
|
||||
- name: storageContainer
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
- job: DeployAzure
|
||||
${{ if ne(length(parameters.pool), 0) }}:
|
||||
pool: ${{ parameters.pool }}
|
||||
displayName: Publish to Azure Storage (Prod)
|
||||
dependsOn: ${{ parameters.dependsOn }}
|
||||
variables:
|
||||
${{ insert }}: ${{ parameters.variables }}
|
||||
steps:
|
||||
- download: none
|
||||
|
||||
- checkout: self
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
fetchTags: false # Tags still result in depth > 1 fetch; we don't need them here
|
||||
submodules: true
|
||||
persistCredentials: True
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download MSIX Bundle Artifact
|
||||
inputs:
|
||||
artifactName: appxbundle-${{ parameters.buildConfiguration }}${{ parameters.artifactStem }}
|
||||
downloadPath: '$(Build.SourcesDirectory)/_out'
|
||||
itemPattern: '**/*.msixbundle'
|
||||
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download unpackaged build for ${{ platform }} ${{ parameters.buildConfiguration }}
|
||||
inputs:
|
||||
artifactName: build-${{ platform }}-${{ parameters.buildConfiguration }}${{ parameters.artifactStem }}
|
||||
downloadPath: '$(Build.SourcesDirectory)/_unpackaged'
|
||||
itemPattern: '**/_unpackaged/*.zip'
|
||||
|
||||
- pwsh: |-
|
||||
$b = Get-Item _out/*.msixbundle
|
||||
./build/scripts/New-AppInstallerFromTemplateAndBundle.ps1 -BundlePath $b.FullName -AppInstallerTemplatePath ./build/config/template.appinstaller -AppInstallerRoot "${{ parameters.storagePublicRootURL }}" -OutputPath _out/Microsoft.WindowsTerminalCanary.appinstaller
|
||||
displayName: "Produce AppInstaller for MSIX bundle"
|
||||
|
||||
- pwsh: |-
|
||||
$zips = Get-ChildItem -Recurse -Filter *.zip _unpackaged
|
||||
$zips | ForEach-Object {
|
||||
$name = $_.Name
|
||||
$parts = $name.Split('_')
|
||||
$parts[1] = "latest"
|
||||
$name = [String]::Join('_', $parts)
|
||||
$_ | Move-Item -Destination (Join-Path "_out" $name)
|
||||
}
|
||||
displayName: "Wrangle Unpackaged builds into place, rename"
|
||||
|
||||
- powershell: |-
|
||||
Get-PackageProvider -Name NuGet -ForceBootstrap
|
||||
Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute
|
||||
displayName: Install Azure Module Dependencies
|
||||
|
||||
- task: AzureFileCopy@5
|
||||
displayName: Publish to Storage Account
|
||||
inputs:
|
||||
sourcePath: _out/*
|
||||
Destination: AzureBlob
|
||||
azureSubscription: ${{ parameters.subscription }}
|
||||
storage: ${{ parameters.storageAccount }}
|
||||
ContainerName: ${{ parameters.storageContainer }}
|
||||
AdditionalArgumentsForBlobCopy: "--content-type application/octet-stream"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
jobs:
|
||||
- job: CodeNavIndexer
|
||||
displayName: Run Github CodeNav Indexer
|
||||
displayName: Run GitHub CodeNav Indexer
|
||||
pool: { vmImage: windows-2022 }
|
||||
|
||||
steps:
|
||||
|
||||
@@ -29,6 +29,9 @@ parameters:
|
||||
- name: publishArtifacts
|
||||
type: boolean
|
||||
default: true
|
||||
- name: afterBuildSteps
|
||||
type: stepList
|
||||
default: []
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.jobName }}
|
||||
@@ -48,6 +51,8 @@ jobs:
|
||||
BundleStemName: Microsoft.WindowsTerminal
|
||||
${{ elseif eq(parameters.branding, 'Preview') }}:
|
||||
BundleStemName: Microsoft.WindowsTerminalPreview
|
||||
${{ elseif eq(parameters.branding, 'Canary') }}:
|
||||
BundleStemName: Microsoft.WindowsTerminalCanary
|
||||
${{ else }}:
|
||||
BundleStemName: WindowsTerminalDev
|
||||
JobOutputDirectory: '$(System.ArtifactsDirectory)/bundle'
|
||||
@@ -83,11 +88,13 @@ jobs:
|
||||
$Components[0] = ([int]$Components[0] + $VersionEpoch)
|
||||
$BundleVersion = $Components -Join "."
|
||||
New-Item -Type Directory "$(System.ArtifactsDirectory)/bundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath 'bin/' -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
$BundlePath = "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath 'bin/' -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath $BundlePath
|
||||
Write-Host "##vso[task.setvariable variable=MsixBundlePath]${BundlePath}"
|
||||
displayName: Create msixbundle
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
- task: EsrpCodeSigning@1
|
||||
- task: EsrpCodeSigning@3
|
||||
displayName: Submit *.msixbundle to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
@@ -137,6 +144,8 @@ jobs:
|
||||
ValidateSignature: true
|
||||
Verbosity: 'Verbose'
|
||||
|
||||
- ${{ parameters.afterBuildSteps }}
|
||||
|
||||
- ${{ if eq(parameters.publishArtifacts, true) }}:
|
||||
- publish: $(JobOutputDirectory)
|
||||
artifact: $(JobOutputArtifactName)
|
||||
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
versionEnvVar: XES_PACKAGEVERSIONNUMBER
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
- task: EsrpCodeSigning@1
|
||||
- task: EsrpCodeSigning@3
|
||||
displayName: Submit *.nupkg to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
|
||||
@@ -17,6 +17,12 @@ parameters:
|
||||
- name: symbolExpiryTime
|
||||
type: string
|
||||
default: 36530 # This is the default from PublishSymbols@2
|
||||
- name: variables
|
||||
type: object
|
||||
default: {}
|
||||
- name: symbolPatGoesInTaskInputs
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.jobName }}
|
||||
@@ -27,6 +33,8 @@ jobs:
|
||||
${{ else }}:
|
||||
displayName: Publish Symbols Internally
|
||||
dependsOn: ${{ parameters.dependsOn }}
|
||||
variables:
|
||||
${{ insert }}: ${{ parameters.variables }}
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
@@ -76,6 +84,8 @@ jobs:
|
||||
SymbolsProduct: 'Windows Terminal Converged Symbols'
|
||||
SymbolsVersion: '$(XES_APPXMANIFESTVERSION)'
|
||||
SymbolExpirationInDays: ${{ parameters.symbolExpiryTime }}
|
||||
${{ if eq(parameters.symbolPatGoesInTaskInputs, true) }}:
|
||||
Pat: $(ADO_microsoftpublicsymbols_PAT)
|
||||
# The ADO task does not support indexing of GitHub sources.
|
||||
# There is a bug which causes this task to fail if LIB includes an inaccessible path (even though it does not depend on it).
|
||||
# To work around this issue, we just force LIB to be any dir that we know exists.
|
||||
@@ -83,4 +93,5 @@ jobs:
|
||||
env:
|
||||
LIB: $(Build.SourcesDirectory)
|
||||
ArtifactServices_Symbol_AccountName: microsoftpublicsymbols
|
||||
ArtifactServices_Symbol_PAT: $(ADO_microsoftpublicsymbols_PAT)
|
||||
${{ if ne(parameters.symbolPatGoesInTaskInputs, true) }}:
|
||||
ArtifactServices_Symbol_PAT: $(ADO_microsoftpublicsymbols_PAT)
|
||||
|
||||
@@ -51,6 +51,9 @@ parameters:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
- name: extraPublishJobs
|
||||
type: object
|
||||
default: []
|
||||
- name: pool
|
||||
type: object
|
||||
default:
|
||||
@@ -58,28 +61,9 @@ parameters:
|
||||
demands: ImageOverride -equals SHINE-VS17-Latest
|
||||
|
||||
variables:
|
||||
# If we are building a branch called "release-*", change the NuGet suffix
|
||||
# to "preview". If we don't do that, XES will set the suffix to "release1"
|
||||
# because it truncates the value after the first period.
|
||||
# We also want to disable the suffix entirely if we're Release branded while
|
||||
# on a release branch.
|
||||
# main is special, however. XES ignores main. Since we never produce actual
|
||||
# shipping builds from main, we want to force it to have a beta label as
|
||||
# well.
|
||||
#
|
||||
# In effect:
|
||||
# BRANCH / BRANDING | Release | Preview
|
||||
# ------------------|----------------------------|-----------------------------
|
||||
# release-* | 1.12.20220427 | 1.13.20220427-preview
|
||||
# main | 1.14.20220427-experimental | 1.14.20220427-experimental
|
||||
# all others | 1.14.20220427-mybranch | 1.14.20220427-mybranch
|
||||
${{ if startsWith(variables['Build.SourceBranchName'], 'release-') }}:
|
||||
${{ if eq(parameters.branding, 'Release') }}:
|
||||
NoNuGetPackBetaVersion: true
|
||||
${{ else }}:
|
||||
NuGetPackBetaVersion: preview
|
||||
${{ elseif eq(variables['Build.SourceBranchName'], 'main') }}:
|
||||
NuGetPackBetaVersion: experimental
|
||||
- template: variables-nuget-package-version.yml
|
||||
parameters:
|
||||
branding: ${{ parameters.branding }}
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
@@ -193,4 +177,5 @@ stages:
|
||||
includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }}
|
||||
symbolExpiryTime: ${{ parameters.symbolExpiryTime }}
|
||||
|
||||
- ${{ parameters.extraPublishJobs }}
|
||||
...
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
parameters:
|
||||
- name: official
|
||||
type: boolean
|
||||
default: false
|
||||
- name: branding
|
||||
type: string
|
||||
default: Release
|
||||
values:
|
||||
- Release
|
||||
- Preview
|
||||
- Canary
|
||||
- Dev
|
||||
- name: buildTerminal
|
||||
type: boolean
|
||||
default: true
|
||||
- name: buildConPTY
|
||||
type: boolean
|
||||
default: false
|
||||
- name: buildWPF
|
||||
type: boolean
|
||||
default: false
|
||||
- name: pgoBuildMode
|
||||
type: string
|
||||
default: Optimize
|
||||
values:
|
||||
- Optimize
|
||||
- Instrument
|
||||
- None
|
||||
- name: buildConfigurations
|
||||
type: object
|
||||
default:
|
||||
- Release
|
||||
- name: buildPlatforms
|
||||
type: object
|
||||
default:
|
||||
- x64
|
||||
- x86
|
||||
- arm64
|
||||
- name: codeSign
|
||||
type: boolean
|
||||
default: true
|
||||
- name: terminalInternalPackageVersion
|
||||
type: string
|
||||
default: '0.0.8'
|
||||
|
||||
- name: publishSymbolsToPublic
|
||||
type: boolean
|
||||
default: true
|
||||
- name: symbolExpiryTime
|
||||
type: string
|
||||
default: 36530 # This is the default from PublishSymbols@2
|
||||
- name: publishVpackToWindows
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
- name: extraPublishJobs
|
||||
type: object
|
||||
default: []
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
- repository: templates
|
||||
type: git
|
||||
name: OneBranch.Pipelines/GovernedTemplates
|
||||
ref: refs/heads/main
|
||||
|
||||
extends:
|
||||
${{ if eq(parameters.official, true) }}:
|
||||
template: v2/Microsoft.Official.yml@templates # https://aka.ms/obpipelines/templates
|
||||
${{ else }}:
|
||||
template: v2/Microsoft.NonOfficial.yml@templates
|
||||
parameters:
|
||||
featureFlags:
|
||||
WindowsHostVersion: 1ESWindows2022
|
||||
platform:
|
||||
name: 'windows_undocked'
|
||||
product: 'Windows Terminal'
|
||||
cloudvault: # https://aka.ms/obpipelines/cloudvault
|
||||
enabled: false
|
||||
globalSdl: # https://aka.ms/obpipelines/sdl
|
||||
tsa:
|
||||
enabled: true
|
||||
configFile: '$(Build.SourcesDirectory)\build\config\tsa.json'
|
||||
binskim:
|
||||
break: false
|
||||
scanOutputDirectoryOnly: true
|
||||
policheck:
|
||||
break: false
|
||||
severity: Note
|
||||
baseline:
|
||||
baselineFile: '$(Build.SourcesDirectory)\build\config\release.gdnbaselines'
|
||||
suppressionSet: default
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
displayName: Build
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./build/pipelines/templates-v2/job-build-project.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: $(JobOutputDirectory)
|
||||
ob_artifactBaseName: $(JobOutputArtifactName)
|
||||
publishArtifacts: false # Handled by OneBranch
|
||||
branding: ${{ parameters.branding }}
|
||||
buildTerminal: ${{ parameters.buildTerminal }}
|
||||
buildConPTY: ${{ parameters.buildConPTY }}
|
||||
buildWPF: ${{ parameters.buildWPF }}
|
||||
pgoBuildMode: ${{ parameters.pgoBuildMode }}
|
||||
buildConfigurations: ${{ parameters.buildConfigurations }}
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
generateSbom: false # this is handled by onebranch
|
||||
removeAllNonSignedFiles: true # appease the overlords
|
||||
codeSign: ${{ parameters.codeSign }}
|
||||
beforeBuildSteps: # Right before we build, lay down the universal package and localizations
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
|
||||
- task: UniversalPackages@0
|
||||
displayName: Download terminal-internal Universal Package
|
||||
inputs:
|
||||
feedListDownload: 2b3f8893-a6e8-411f-b197-a9e05576da48
|
||||
packageListDownload: e82d490c-af86-4733-9dc4-07b772033204
|
||||
versionListDownload: ${{ parameters.terminalInternalPackageVersion }}
|
||||
|
||||
- template: ./build/pipelines/templates-v2/steps-fetch-and-prepare-localizations.yml@self
|
||||
parameters:
|
||||
includePseudoLoc: true
|
||||
|
||||
- ${{ if eq(parameters.buildWPF, true) }}:
|
||||
# Add an Any CPU build flavor for the WPF control bits
|
||||
- template: ./build/pipelines/templates-v2/job-build-project.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: $(JobOutputDirectory)
|
||||
ob_artifactBaseName: $(JobOutputArtifactName)
|
||||
publishArtifacts: false # Handled by OneBranch
|
||||
jobName: BuildWPF
|
||||
branding: ${{ parameters.branding }}
|
||||
buildTerminal: false
|
||||
buildWPFDotNetComponents: true
|
||||
buildConfigurations: ${{ parameters.buildConfigurations }}
|
||||
buildPlatforms:
|
||||
- Any CPU
|
||||
generateSbom: false # this is handled by onebranch
|
||||
removeAllNonSignedFiles: true # appease the overlords
|
||||
codeSign: ${{ parameters.codeSign }}
|
||||
beforeBuildSteps:
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
# WPF doesn't need the localizations or the universal package, but if it does... put them here.
|
||||
|
||||
- stage: Package
|
||||
displayName: Package
|
||||
dependsOn: [Build]
|
||||
jobs:
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- template: ./build/pipelines/templates-v2/job-merge-msix-into-bundle.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: $(JobOutputDirectory)
|
||||
ob_artifactBaseName: $(JobOutputArtifactName)
|
||||
### This job is also in charge of submitting the vpack to Windows if it's enabled
|
||||
ob_createvpack_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
|
||||
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
|
||||
### If enabled above, these options are in play.
|
||||
ob_createvpack_packagename: 'WindowsTerminal.app'
|
||||
ob_createvpack_owneralias: 'conhost@microsoft.com'
|
||||
ob_createvpack_description: 'VPack for the Windows Terminal Application'
|
||||
ob_createvpack_targetDestinationDirectory: '$(Destination)'
|
||||
ob_createvpack_propsFile: false
|
||||
ob_createvpack_provData: true
|
||||
ob_createvpack_metadata: '$(Build.SourceVersion)'
|
||||
ob_createvpack_topLevelRetries: 0
|
||||
ob_createvpack_failOnStdErr: true
|
||||
ob_createvpack_taskLogVerbosity: Detailed
|
||||
ob_createvpack_verbose: true
|
||||
ob_createvpack_vpackdirectory: '$(JobOutputDirectory)\vpack'
|
||||
ob_updateOSManifest_gitcheckinConfigPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
|
||||
# We're skipping the 'fetch' part of the OneBranch rules, but that doesn't mean
|
||||
# that it doesn't expect to have downloaded a manifest directly to some 'destination'
|
||||
# folder that it can then update and upload.
|
||||
# Effectively: it says "destination" but it means "source"
|
||||
# DH: Don't ask why.
|
||||
ob_updateOSManifest_destination: $(XES_VPACKMANIFESTDIRECTORY)
|
||||
ob_updateOSManifest_skipFetch: true
|
||||
publishArtifacts: false # Handled by OneBranch
|
||||
jobName: Bundle
|
||||
branding: ${{ parameters.branding }}
|
||||
buildConfigurations: ${{ parameters.buildConfigurations }}
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
generateSbom: false # Handled by onebranch
|
||||
codeSign: ${{ parameters.codeSign }}
|
||||
afterBuildSteps:
|
||||
# This directory has to exist, even if we aren't using createvpack, because the Guardian rules demand it.
|
||||
- pwsh: |-
|
||||
New-Item "$(JobOutputDirectory)/vpack" -Type Directory
|
||||
displayName: Make sure the vpack directory exists
|
||||
|
||||
- ${{ if parameters.publishVpackToWindows }}:
|
||||
- pwsh: |-
|
||||
Copy-Item -Verbose -Path "$(MsixBundlePath)" -Destination (Join-Path "$(JobOutputDirectory)/vpack" 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle')
|
||||
displayName: Stage msixbundle for vpack
|
||||
|
||||
- ${{ if eq(parameters.buildConPTY, true) }}:
|
||||
- template: ./build/pipelines/templates-v2/job-package-conpty.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: $(JobOutputDirectory)
|
||||
ob_artifactBaseName: $(JobOutputArtifactName)
|
||||
publishArtifacts: false # Handled by OneBranch
|
||||
buildConfigurations: ${{ parameters.buildConfigurations }}
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
generateSbom: false # this is handled by onebranch
|
||||
codeSign: ${{ parameters.codeSign }}
|
||||
|
||||
- ${{ if eq(parameters.buildWPF, true) }}:
|
||||
- template: ./build/pipelines/templates-v2/job-build-package-wpf.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: $(JobOutputDirectory)
|
||||
ob_artifactBaseName: $(JobOutputArtifactName)
|
||||
publishArtifacts: false # Handled by OneBranch
|
||||
buildConfigurations: ${{ parameters.buildConfigurations }}
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
generateSbom: false # this is handled by onebranch
|
||||
codeSign: ${{ parameters.codeSign }}
|
||||
|
||||
- stage: Publish
|
||||
displayName: Publish
|
||||
dependsOn: [Build, Package]
|
||||
jobs:
|
||||
- template: ./build/pipelines/templates-v2/job-publish-symbols.yml@self
|
||||
parameters:
|
||||
pool: { type: windows }
|
||||
includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }}
|
||||
symbolPatGoesInTaskInputs: true # onebranch tries to muck with the PAT variable, so we need to change how it get the PAT
|
||||
symbolExpiryTime: ${{ parameters.symbolExpiryTime }}
|
||||
variables:
|
||||
ob_git_checkout: false # This job checks itself out
|
||||
ob_git_skip_checkout_none: true
|
||||
ob_outputDirectory: $(Build.ArtifactStagingDirectory)
|
||||
# Without this, OneBranch will nerf our symbol tasks
|
||||
ob_symbolsPublishing_enabled: true
|
||||
|
||||
- ${{ parameters.extraPublishJobs }}
|
||||
@@ -0,0 +1,27 @@
|
||||
parameters:
|
||||
- name: branding
|
||||
type: string
|
||||
|
||||
variables:
|
||||
# If we are building a branch called "release-*", change the NuGet suffix
|
||||
# to "preview". If we don't do that, XES will set the suffix to "release1"
|
||||
# because it truncates the value after the first period.
|
||||
# We also want to disable the suffix entirely if we're Release branded while
|
||||
# on a release branch.
|
||||
# main is special, however. XES ignores main. Since we never produce actual
|
||||
# shipping builds from main, we want to force it to have a beta label as
|
||||
# well.
|
||||
#
|
||||
# In effect:
|
||||
# BRANCH / BRANDING | Release | Preview
|
||||
# ------------------|----------------------------|-----------------------------
|
||||
# release-* | 1.12.20220427 | 1.13.20220427-preview
|
||||
# main | 1.14.20220427-experimental | 1.14.20220427-experimental
|
||||
# all others | 1.14.20220427-mybranch | 1.14.20220427-mybranch
|
||||
${{ if startsWith(variables['Build.SourceBranchName'], 'release-') }}:
|
||||
${{ if eq(parameters.branding, 'Release') }}:
|
||||
NoNuGetPackBetaVersion: true
|
||||
${{ else }}:
|
||||
NuGetPackBetaVersion: preview
|
||||
${{ elseif eq(variables['Build.SourceBranchName'], 'main') }}:
|
||||
NuGetPackBetaVersion: experimental
|
||||
@@ -0,0 +1,2 @@
|
||||
variables:
|
||||
WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest'
|
||||
42
build/scripts/New-AppInstallerFromTemplateAndBundle.ps1
Normal file
42
build/scripts/New-AppInstallerFromTemplateAndBundle.ps1
Normal file
@@ -0,0 +1,42 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Path to the .msixbundle")]
|
||||
[string]
|
||||
$BundlePath,
|
||||
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Path to the .appinstaller template")]
|
||||
[string]
|
||||
$AppInstallerTemplatePath,
|
||||
|
||||
[string]
|
||||
$AppInstallerRoot,
|
||||
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Output Path")]
|
||||
[string]
|
||||
$OutputPath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$sentinelFile = New-TemporaryFile
|
||||
$directory = New-Item -Type Directory "$($sentinelFile.FullName)_Package"
|
||||
Remove-Item $sentinelFile -Force -EA:Ignore
|
||||
|
||||
$bundle = (Get-Item $BundlePath)
|
||||
& tar.exe -x -f $bundle.FullName -C $directory AppxMetadata/AppxBundleManifest.xml
|
||||
|
||||
$xml = [xml](Get-Content (Join-Path $directory "AppxMetadata\AppxBundleManifest.xml"))
|
||||
$name = $xml.Bundle.Identity.Name
|
||||
$version = $xml.Bundle.Identity.Version
|
||||
|
||||
$doc = (Get-Content -ReadCount 0 $AppInstallerTemplatePath)
|
||||
$doc = $doc -Replace '\$\$ROOT\$\$',$AppInstallerRoot
|
||||
$doc = $doc -Replace '\$\$NAME\$\$',$name
|
||||
$doc = $doc -Replace '\$\$VERSION\$\$',$version
|
||||
$doc = $doc -Replace '\$\$PACKAGE\$\$',$bundle.Name
|
||||
$doc | Out-File -Encoding utf8NoBOM $OutputPath
|
||||
|
||||
Get-Item $OutputPath
|
||||
@@ -25,7 +25,12 @@ Param(
|
||||
[Parameter(HelpMessage="Path to makeappx.exe", ParameterSetName='Layout')]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakeAppx.exe"
|
||||
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakeAppx.exe",
|
||||
|
||||
[Parameter(HelpMessage="Include the portable mode marker file by default", ParameterSetName='AppX')]
|
||||
[Parameter(HelpMessage="Include the portable mode marker file by default", ParameterSetName='Layout')]
|
||||
[switch]
|
||||
$PortableMode = $PSCmdlet.ParameterSetName -eq 'Layout'
|
||||
)
|
||||
|
||||
$filesToRemove = @("*.xml", "*.winmd", "Appx*", "Images/*Tile*", "Images/*Logo*") # Remove from Terminal
|
||||
@@ -128,6 +133,11 @@ $finalTerminalPriFile = Join-Path $terminalAppPath "resources.pri"
|
||||
# Packaging
|
||||
########
|
||||
|
||||
$portableModeMarkerFile = Join-Path $terminalAppPath ".portable"
|
||||
If ($PortableMode) {
|
||||
"" | Out-File $portableModeMarkerFile
|
||||
}
|
||||
|
||||
If ($PSCmdlet.ParameterSetName -Eq "AppX") {
|
||||
# We only produce a ZIP when we're combining two AppX directories.
|
||||
New-Item -ItemType Directory -Path $Destination -ErrorAction:SilentlyContinue | Out-Null
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2023</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>19</VersionMinor>
|
||||
<VersionMinor>20</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220201.1" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230824.2" targetFramework="native" developmentDependency="true" />
|
||||
|
||||
<!-- Managed packages -->
|
||||
<package id="Appium.WebDriver" version="3.0.0.2" targetFramework="net45" />
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
`.../console/published/wincon.w` in the OS repo when you submit the PR.
|
||||
The branch won't build without it.
|
||||
* For now, you can update winconp.h with your consumable changes.
|
||||
* Define registry name (ex `CONSOLE_REGISTRY_CURSORCOLOR`)
|
||||
* Add the setting to `CONSOLE_STATE_INFO`
|
||||
* Define registry name (ex: `CONSOLE_REGISTRY_CURSORCOLOR`)
|
||||
* Add the setting to `CONSOLE_STATE_INFO`.
|
||||
* Define the property key ID and the property key itself.
|
||||
- Yes, the large majority of the `DEFINE_PROPERTYKEY` defs are the same, it's only the last byte of the guid that changes
|
||||
- Yes, the large majority of the `DEFINE_PROPERTYKEY` defs are the same, it's only the last byte of the guid that changes.
|
||||
|
||||
2. Add matching fields to Settings.hpp
|
||||
- Add getters, setters, the whole drill.
|
||||
@@ -17,9 +17,9 @@
|
||||
- We need to add it to *reading and writing* the registry from the propsheet, and *reading* the link from the propsheet. Yes, that's weird, but the propsheet is smart enough to re-use ShortcutSerialization::s_SetLinkValues, but not smart enough to do the same with RegistrySerialization.
|
||||
- `src/propsheet/registry.cpp`
|
||||
- `propsheet/registry.cpp@InitRegistryValues` should initialize the default value for the property.
|
||||
- `propsheet/registry.cpp@GetRegistryValues` should make sure to read the property from the registry
|
||||
- `propsheet/registry.cpp@GetRegistryValues` should make sure to read the property from the registry.
|
||||
|
||||
4. Add the field to the propslib registry map
|
||||
4. Add the field to the propslib registry map.
|
||||
|
||||
5. Add the value to `ShortcutSerialization.cpp`
|
||||
- Read the value in `ShortcutSerialization::s_PopulateV2Properties`
|
||||
@@ -30,11 +30,11 @@ Now, your new setting should be stored just like all the other properties.
|
||||
|
||||
7. Update the feature test properties to get add the setting as well
|
||||
- `ft_uia/Common/NativeMethods.cs@WinConP`:
|
||||
- `Wtypes.PROPERTYKEY PKEY_Console_`
|
||||
- `NT_CONSOLE_PROPS`
|
||||
- `Wtypes.PROPERTYKEY PKEY_Console_`.
|
||||
- `NT_CONSOLE_PROPS`.
|
||||
|
||||
8. Add the default value for the setting to `win32k-settings.man`
|
||||
- If the setting shouldn't default to 0 or `nullptr`, then you'll need to set the default value of the setting in `win32k-settings.man`.
|
||||
|
||||
9. Update `Settings::InitFromStateInfo` and `Settings::CreateConsoleStateInfo` to get/set the value in a CONSOLE_STATE_INFO appropriately
|
||||
9. Update `Settings::InitFromStateInfo` and `Settings::CreateConsoleStateInfo` to get/set the value in a CONSOLE_STATE_INFO appropriately.
|
||||
|
||||
|
||||
96
doc/COOKED_READ_DATA.md
Normal file
96
doc/COOKED_READ_DATA.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# COOKED_READ_DATA, aka conhost's readline implementation
|
||||
|
||||
## Test instructions
|
||||
|
||||
All of the following ✅ marks must be fulfilled during manual testing:
|
||||
* ASCII input
|
||||
* Chinese input (中文維基百科) ❔
|
||||
* Resizing the window properly wraps/unwraps wide glyphs ❌
|
||||
Broken due to `TextBuffer::Reflow` bugs
|
||||
* Surrogate pair input (🙂) ❔
|
||||
* Resizing the window properly wraps/unwraps surrogate pairs ❌
|
||||
Broken due to `TextBuffer::Reflow` bugs
|
||||
* In cmd.exe
|
||||
* Create 2 file: "a😊b.txt" and "a😟b.txt"
|
||||
* Press tab: Autocomplete to "a😊b.txt" ✅
|
||||
* Navigate the cursor right past the "a"
|
||||
* Press tab twice: Autocomplete to "a😟b.txt" ✅
|
||||
* Execute `printf(" "); gets(buffer);` in C (or equivalent)
|
||||
* Press Tab, A, Ctrl+V, Tab, A ✅
|
||||
* The prompt is " A^V A" ✅
|
||||
* Cursor navigation works ✅
|
||||
* Backspacing/Deleting random parts of it works ✅
|
||||
* It never deletes the initial 4 spaces ✅
|
||||
* Backspace deletes preceding glyphs ✅
|
||||
* Ctrl+Backspace deletes preceding words ✅
|
||||
* Escape clears input ✅
|
||||
* Home navigates to start ✅
|
||||
* Ctrl+Home deletes text between cursor and start ✅
|
||||
* End navigates to end ✅
|
||||
* Ctrl+End deletes text between cursor and end ✅
|
||||
* Left navigates over previous code points ✅
|
||||
* Ctrl+Left navigates to previous word-starts ✅
|
||||
* Right and F1 navigate over next code points ✅
|
||||
* Pressing right at the end of input copies characters
|
||||
from the previous command ✅
|
||||
* Ctrl+Right navigates to next word-ends ✅
|
||||
* Insert toggles overwrite mode ✅
|
||||
* Delete deletes next code point ✅
|
||||
* Up and F5 cycle through history ✅
|
||||
* Doesn't crash with no history ✅
|
||||
* Stops at first entry ✅
|
||||
* Down cycles through history ✅
|
||||
* Doesn't crash with no history ✅
|
||||
* Stops at last entry ✅
|
||||
* PageUp retrieves the oldest command ✅
|
||||
* PageDown retrieves the newest command ✅
|
||||
* F2 starts "copy to char" prompt ✅
|
||||
* Escape dismisses prompt ✅
|
||||
* Typing a character copies text from the previous command up
|
||||
until that character into the current buffer (acts identical
|
||||
to F3, but with automatic character search) ✅
|
||||
* F3 copies the previous command into the current buffer,
|
||||
starting at the current cursor position,
|
||||
for as many characters as possible ✅
|
||||
* Doesn't erase trailing text if the current buffer
|
||||
is longer than the previous command ✅
|
||||
* Puts the cursor at the end of the copied text ✅
|
||||
* F4 starts "copy from char" prompt ✅
|
||||
* Escape dismisses prompt ✅
|
||||
* Erases text between the current cursor position and the
|
||||
first instance of a given char (but not including it) ✅
|
||||
* F6 inserts Ctrl+Z ✅
|
||||
* F7 without modifiers starts "command list" prompt ✅
|
||||
* Escape dismisses prompt ✅
|
||||
* Minimum size of 40x10 characters ✅
|
||||
* Width expands to fit the widest history command ✅
|
||||
* Height expands up to 20 rows with longer histories ✅
|
||||
* F9 starts "command number" prompt ✅
|
||||
* Left/Right paste replace the buffer with the given command ✅
|
||||
* And put cursor at the end of the buffer ✅
|
||||
* Up/Down navigate selection through history ✅
|
||||
* Stops at start/end with <10 entries ✅
|
||||
* Stops at start/end with >20 entries ✅
|
||||
* Wide text rendering during pagination with >20 entries ✅
|
||||
* Shift+Up/Down moves history items around ✅
|
||||
* Home navigates to first entry ✅
|
||||
* End navigates to last entry ✅
|
||||
* PageUp navigates by 20 items at a time or to first ✅
|
||||
* PageDown navigates by 20 items at a time or to last ✅
|
||||
* Alt+F7 clears command history ✅
|
||||
* F8 cycles through commands that start with the same text as
|
||||
the current buffer up until the current cursor position ✅
|
||||
* Doesn't crash with no history ✅
|
||||
* F9 starts "command number" prompt ✅
|
||||
* Escape dismisses prompt ✅
|
||||
* Ignores non-ASCII-decimal characters ✅
|
||||
* Allows entering between 1 and 5 digits ✅
|
||||
* Pressing Enter fetches the given command from the history ✅
|
||||
* Alt+F10 clears doskey aliases ✅
|
||||
* In cmd.exe, with an empty prompt in an empty directory:
|
||||
Pressing tab produces an audible bing and prints no text ✅
|
||||
* When Narrator is enabled, in cmd.exe:
|
||||
* Typing individual characters announces only
|
||||
exactly each character that is being typed ✅
|
||||
* Backspacing at the end of a prompt announces
|
||||
only exactly each deleted character ✅
|
||||
@@ -27,6 +27,8 @@ I would highly recommend that Gulp convert to using PowerShell scripts and that
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/217#issuecomment-404240443
|
||||
|
||||
_Addendum_: cmd.exe is the literal embodiment of [xkcd#1172]([url](https://xkcd.com/1172/)). Every change, no matter how small, will break _someone_.
|
||||
|
||||
## <a name="screenPerf"></a>Why is typing-to-screen performance better than every other app?
|
||||
|
||||
I really do not mind when someone comes by and decides to tell us that we're doing a good job at something. We hear so many complaints every day that a post like this is a breath of fresh air. Thanks for your thanks!
|
||||
@@ -49,7 +51,7 @@ Will this UI enhancement come to other apps on Windows? Almost certainly not. Th
|
||||
|
||||
Will we try to keep it from regressing? Yes! Right now it's sort of a manual process. We identify that something is getting slow and then we go haul out [WPR](https://docs.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-recorder) and start taking traces. We stare down the hot paths and try to reason out what is going on and then improve them. For instance, in the last cycle or two, we focused on heap allocations as a major area where we could improve our end-to-end performance, changing a ton of our code to use stack-constructed iterator-like facades over the underlying request buffer instead of translating and allocating it into a new heap space for each level of processing.
|
||||
|
||||
As an aside, @bitcrazed wants us to automate performance tests in some conhost specific way, but I haven't quite figured out a controlled environment to do this in yet. The Windows Engineering System runs performance tests each night that give us a coarse grained way of knowing if we messed something up for the whole operating system, and they technically offer a fine grained way for us to insert our own performance tests... but I just haven't got around to that yet. If you have an idea for a way for us to do this in an automated fashion, I'm all ears.
|
||||
As an aside, @bitcrazed wants us to automate performance tests in some conhost specific way, but I haven't quite figured out a controlled environment to do this in yet. The Windows Engineering System runs performance tests each night that give us a coarse-grained way of knowing if we messed something up for the whole operating system, and they technically offer a fine-grained way for us to insert our own performance tests... but I just haven't got around to that yet. If you have an idea for a way for us to do this in an automated fashion, I'm all ears.
|
||||
|
||||
If there's anything else you'd like to know, let me know. I could go on all day. I deleted like 15 tangents from this reply before posting it....
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
* `/src/cascadia/TerminalApp` - This DLL represents the implementation of the Windows Terminal application. This includes parsing settings, hosting tabs & panes with Terminals in them, and displaying other UI elements. This DLL is almost entirely UWP-like code, and shouldn't be doing any Win32-like UI work.
|
||||
* `/src/cascadia/WindowsTerminal` - This EXE provides Win32 hosting for the TerminalApp. It will set up XAML islands, and is responsible for drawing the window, either as a standard window or with content in the titlebar (non-client area).
|
||||
* `/src/cascadia/CascadiaPackage` - This is a project for packaging the Windows Terminal and its dependencies into an .appx/.msix for deploying to the machine.
|
||||
* `/src/cascadia/PublicTerminalCore` - This is a DLL wrapper for the TerminalCore and Renderer, similar to `TermControl`, which exposes some exported functions that so the Terminal can be used from C#.
|
||||
* `/src/cascadia/WpfTerminalControl` - A DLL implementing a WPF version of the Terminal Control.
|
||||
* `/src/host` – The meat of the windows console host. This includes buffer, input, output, windowing, server management, clipboard, and most interactions with the console host window that aren’t stated anywhere else. We’re trying to pull things out that are reusable into other libraries, but it’s a work in progress
|
||||
* `/src/host/lib` – Builds the reusable LIB copy of the host
|
||||
@@ -126,8 +125,6 @@
|
||||
* Private calls into the Windows Window Manager to perform privileged actions related to the console process (working to eliminate) or for High DPI stuff (also working to eliminate)
|
||||
* `Userprivapi.cpp`
|
||||
* `Windowdpiapi.cpp`
|
||||
* New UTF8 state machine in progress to improve Bash (and other apps) support for UTF-8 in console
|
||||
* `Utf8ToWideCharParser.cpp`
|
||||
* Window resizing/layout/management/window messaging loops and all that other stuff that has us interact with Windows to create a visual display surface and control the user interaction entry point
|
||||
* `Window.cpp`
|
||||
* `Windowproc.cpp`
|
||||
|
||||
@@ -86,12 +86,19 @@
|
||||
]
|
||||
},
|
||||
"BuiltinSuggestionSource": {
|
||||
"enum": [
|
||||
"commandHistory",
|
||||
"tasks",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"commandHistory",
|
||||
"tasks",
|
||||
"all"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"SuggestionSource": {
|
||||
"default": "all",
|
||||
@@ -99,15 +106,17 @@
|
||||
"$comment": "`tasks` and `local` are sources that would be added by the Tasks feature, as a follow-up",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": [ "string", "null", "BuiltinSuggestionSource" ]
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/BuiltinSuggestionSource"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": { "type": "BuiltinSuggestionSource" }
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
"items": {
|
||||
"$ref": "#/$defs/BuiltinSuggestionSource"
|
||||
},
|
||||
"uniqueItems": true
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -201,10 +210,6 @@
|
||||
"desktopWallpaper"
|
||||
]
|
||||
}
|
||||
],
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"backgroundImageOpacity": {
|
||||
@@ -269,6 +274,17 @@
|
||||
"experimental.pixelShaderPath": {
|
||||
"description": "Use to set a path to a pixel shader to use with the Terminal when unfocused. Overrides `experimental.retroTerminalEffect`. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "string"
|
||||
},
|
||||
"useAcrylic": {
|
||||
"description": "When set to true, the window will have an acrylic material background when unfocused. When set to false, the window will have a plain, untextured background when unfocused.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"opacity": {
|
||||
"default": 100,
|
||||
"description": "Sets the opacity of the window for the profile when unfocused. Accepts values from 0-100.",
|
||||
"maximum": 100,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -374,8 +390,12 @@
|
||||
},
|
||||
"ShortcutActionName": {
|
||||
"enum": [
|
||||
"addMark",
|
||||
"adjustFontSize",
|
||||
"adjustOpacity",
|
||||
"clearAllMarks",
|
||||
"clearBuffer",
|
||||
"clearMark",
|
||||
"closeOtherPanes",
|
||||
"closeOtherTabs",
|
||||
"closePane",
|
||||
@@ -386,6 +406,7 @@
|
||||
"copy",
|
||||
"duplicateTab",
|
||||
"expandSelectionToWord",
|
||||
"experimental.colorSelection",
|
||||
"exportBuffer",
|
||||
"find",
|
||||
"findMatch",
|
||||
@@ -393,64 +414,60 @@
|
||||
"globalSummon",
|
||||
"identifyWindow",
|
||||
"identifyWindows",
|
||||
"markMode",
|
||||
"moveFocus",
|
||||
"movePane",
|
||||
"swapPane",
|
||||
"markMode",
|
||||
"moveTab",
|
||||
"multipleActions",
|
||||
"newTab",
|
||||
"newWindow",
|
||||
"nextTab",
|
||||
"openAbout",
|
||||
"openNewTabDropdown",
|
||||
"openSettings",
|
||||
"openSystemMenu",
|
||||
"openTabColorPicker",
|
||||
"openTabRenamer",
|
||||
"openWindowRenamer",
|
||||
"paste",
|
||||
"prevTab",
|
||||
"renameTab",
|
||||
"openSystemMenu",
|
||||
"openTabRenamer",
|
||||
"quakeMode",
|
||||
"quit",
|
||||
"renameTab",
|
||||
"renameWindow",
|
||||
"resetFontSize",
|
||||
"resizePane",
|
||||
"renameWindow",
|
||||
"restoreLastClosed",
|
||||
"scrollDown",
|
||||
"scrollDownPage",
|
||||
"scrollToBottom",
|
||||
"scrollToMark",
|
||||
"scrollToTop",
|
||||
"scrollUp",
|
||||
"scrollUpPage",
|
||||
"scrollToBottom",
|
||||
"scrollToTop",
|
||||
"searchWeb",
|
||||
"selectAll",
|
||||
"sendInput",
|
||||
"setColorScheme",
|
||||
"setFocusMode",
|
||||
"setFullScreen",
|
||||
"setMaximized",
|
||||
"setTabColor",
|
||||
"showSuggestions",
|
||||
"splitPane",
|
||||
"swapPane",
|
||||
"switchSelectionEndpoint",
|
||||
"switchToTab",
|
||||
"tabSearch",
|
||||
"toggleAlwaysOnTop",
|
||||
"toggleBlockSelection",
|
||||
"toggleFocusMode",
|
||||
"selectAll",
|
||||
"setFocusMode",
|
||||
"switchSelectionEndpoint",
|
||||
"toggleFullscreen",
|
||||
"setFullScreen",
|
||||
"setMaximized",
|
||||
"togglePaneZoom",
|
||||
"toggleSplitOrientation",
|
||||
"toggleReadOnlyMode",
|
||||
"toggleShaderEffects",
|
||||
"toggleSplitOrientation",
|
||||
"wt",
|
||||
"quit",
|
||||
"adjustOpacity",
|
||||
"restoreLastClosed",
|
||||
"addMark",
|
||||
"scrollToMark",
|
||||
"clearMark",
|
||||
"clearAllMarks",
|
||||
"searchWeb",
|
||||
"experimental.colorSelection",
|
||||
"unbound"
|
||||
],
|
||||
"type": "string"
|
||||
@@ -640,6 +657,7 @@
|
||||
"$ref": "#/$defs/NewTabMenuEntry"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
@@ -668,7 +686,7 @@
|
||||
},
|
||||
"allowEmpty": {
|
||||
"description": "Whether to render a folder without entries, or to hide it",
|
||||
"default": "false",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -682,6 +700,7 @@
|
||||
"$ref": "#/$defs/NewTabMenuEntry"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
@@ -698,6 +717,7 @@
|
||||
"$ref": "#/$defs/NewTabMenuEntry"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
@@ -719,6 +739,7 @@
|
||||
"$ref": "#/$defs/NewTabMenuEntry"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
@@ -735,6 +756,7 @@
|
||||
"$ref": "#/$defs/NewTabMenuEntry"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
@@ -775,6 +797,7 @@
|
||||
]
|
||||
},
|
||||
"ShortcutAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"description": "The action to execute",
|
||||
@@ -783,8 +806,7 @@
|
||||
},
|
||||
"required": [
|
||||
"action"
|
||||
],
|
||||
"type": "object"
|
||||
]
|
||||
},
|
||||
"AdjustFontSizeAction": {
|
||||
"description": "Arguments corresponding to an Adjust Font Size Action",
|
||||
@@ -793,6 +815,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -817,6 +840,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -858,6 +882,7 @@
|
||||
"$ref": "#/$defs/NewTerminalArgs"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -874,6 +899,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -898,6 +924,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -922,6 +949,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -946,6 +974,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -970,6 +999,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -994,6 +1024,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1018,6 +1049,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1045,6 +1077,7 @@
|
||||
"$ref": "#/$defs/NewTerminalArgs"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1077,6 +1110,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1114,6 +1148,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1141,6 +1176,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1162,6 +1198,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1183,6 +1220,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1207,6 +1245,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1227,6 +1266,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1247,6 +1287,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1267,6 +1308,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1291,6 +1333,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1319,6 +1362,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1347,6 +1391,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1375,6 +1420,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1399,6 +1445,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1423,6 +1470,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1446,6 +1494,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1471,6 +1520,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1492,6 +1542,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1519,6 +1570,7 @@
|
||||
"$ref": "#/$defs/NewTerminalArgs"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1535,6 +1587,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1556,6 +1609,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1577,6 +1631,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1598,6 +1653,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1619,6 +1675,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1641,6 +1698,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1662,6 +1720,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1683,6 +1742,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1734,6 +1794,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1750,6 +1811,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1773,6 +1835,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1801,6 +1864,7 @@
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
@@ -1887,7 +1951,11 @@
|
||||
"properties": {
|
||||
"applicationTheme": {
|
||||
"description": "Which UI theme the Terminal should use for controls",
|
||||
"enum": [ "light", "dark", "system" ],
|
||||
"enum": [
|
||||
"light",
|
||||
"dark",
|
||||
"system"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"useMica": {
|
||||
@@ -1918,7 +1986,11 @@
|
||||
"type": "string",
|
||||
"description": "The name of the theme. This will be displayed in the settings UI.",
|
||||
"not": {
|
||||
"enum": [ "light", "dark", "system" ]
|
||||
"enum": [
|
||||
"light",
|
||||
"dark",
|
||||
"system"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tab": {
|
||||
@@ -1935,6 +2007,7 @@
|
||||
"ThemePair": {
|
||||
"additionalProperties": false,
|
||||
"description": "A pair of Theme names, to allow the Terminal to switch theme based on the OS theme",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"light": {
|
||||
"type": "string",
|
||||
@@ -2116,16 +2189,16 @@
|
||||
},
|
||||
"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.\nIf name is a string, it will be the name of the command.\nIf name is a object, the key property of the object will be used to lookup a localized string resource for the command",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": [
|
||||
"string",
|
||||
"object",
|
||||
"null"
|
||||
]
|
||||
],
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"iterateOn": {
|
||||
"type": "string",
|
||||
@@ -2162,6 +2235,7 @@
|
||||
"Globals": {
|
||||
"additionalProperties": true,
|
||||
"description": "Properties that affect the entire window, regardless of the profile settings.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"alwaysOnTop": {
|
||||
"default": false,
|
||||
@@ -2173,6 +2247,11 @@
|
||||
"description": "When set to true, tabs are always displayed. When set to false and \"showTabsInTitlebar\" is set to false, tabs only appear after opening a new tab.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"compatibility.enableUnfocusedAcrylic": {
|
||||
"default": true,
|
||||
"description": "When set to true, unfocused windows can have acrylic instead of opaque.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"centerOnLaunch": {
|
||||
"default": false,
|
||||
"description": "When set to `true`, the terminal window will auto-center itself on the display it opens on. The terminal will use the \"initialPosition\" to determine which display to open on.",
|
||||
@@ -2270,11 +2349,6 @@
|
||||
"description": "When set to true, the background image for the currently focused profile is expanded to encompass the entire window, beneath other panes.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"compatibility.reloadEnvironmentVariables": {
|
||||
"default": true,
|
||||
"description": "When set to true, when opening a new tab or pane it will get reloaded environment variables.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"initialCols": {
|
||||
"default": 120,
|
||||
"description": "The number of columns displayed in the window upon first load. If \"launchMode\" is set to \"maximized\" (or \"maximizedFocus\"), this property is ignored.",
|
||||
@@ -2376,10 +2450,17 @@
|
||||
"theme": {
|
||||
"default": "dark",
|
||||
"description": "Sets the theme of the application. This value should be the name of one of the themes defined in `themes`. The Terminal also includes the themes `dark`, `light`, and `system`.",
|
||||
"oneOf": [
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"dark",
|
||||
"light",
|
||||
"system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/ThemePair"
|
||||
}
|
||||
@@ -2489,12 +2570,12 @@
|
||||
},
|
||||
"required": [
|
||||
"defaultProfile"
|
||||
],
|
||||
"type": "object"
|
||||
]
|
||||
},
|
||||
"Profile": {
|
||||
"description": "Properties specific to a unique profile.",
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"acrylicOpacity": {
|
||||
"default": 0.5,
|
||||
@@ -2523,6 +2604,11 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"compatibility.reloadEnvironmentVariables": {
|
||||
"default": true,
|
||||
"description": "When set to true, when opening a new tab or pane it will get reloaded environment variables.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"unfocusedAppearance": {
|
||||
"$ref": "#/$defs/AppearanceConfig",
|
||||
"description": "Sets the appearance of the terminal when it is unfocused.",
|
||||
@@ -2541,7 +2627,7 @@
|
||||
},
|
||||
"backgroundImage": {
|
||||
"description": "Sets the file location of the image to draw over the window background.",
|
||||
"oneOf": [
|
||||
"anyOf": [
|
||||
{
|
||||
"type": [
|
||||
"string",
|
||||
@@ -2553,10 +2639,6 @@
|
||||
"desktopWallpaper"
|
||||
]
|
||||
}
|
||||
],
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"backgroundImageAlignment": {
|
||||
@@ -2893,8 +2975,7 @@
|
||||
"description": "When set to true, the window will have an acrylic material background. When set to false, the window will have a plain, untextured background.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"ProfileList": {
|
||||
"description": "A list of profiles and the properties specific to each.",
|
||||
@@ -2909,6 +2990,7 @@
|
||||
},
|
||||
"ProfilesObject": {
|
||||
"description": "A list of profiles and default settings that apply to all of them",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"$ref": "#/$defs/ProfileList"
|
||||
@@ -2917,12 +2999,12 @@
|
||||
"description": "The default settings that apply to every profile.",
|
||||
"$ref": "#/$defs/Profile"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"SchemeList": {
|
||||
"description": "Properties are specific to each color scheme. ColorTool is a great tool you can use to create and explore new color schemes. All colors use hex color format.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
@@ -3011,8 +3093,7 @@
|
||||
"$ref": "#/$defs/Color",
|
||||
"description": "Sets the color used as ANSI yellow."
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
@@ -3022,6 +3103,7 @@
|
||||
"$ref": "#/$defs/Globals"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalItems": true,
|
||||
"properties": {
|
||||
"profiles": {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Terminal 2022 Roadmap
|
||||
|
||||
> **NOTE**
|
||||
>
|
||||
> This document has been superseded by the [Terminal 2023 Roadmap]. Please refer to that document for the updated roadmap.
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the roadmap of features we're planning for the Windows Terminal during 2022. This serves as a successor to the [Terminal v2 Roadmap], to reflect changes to our planning going forward.
|
||||
@@ -111,7 +115,7 @@ Incoming issues/asks/etc. are triaged several times a week, labeled appropriatel
|
||||
[Up Next]: https://github.com/microsoft/terminal/milestone/37
|
||||
[Backlog]: https://github.com/microsoft/terminal/milestone/45
|
||||
|
||||
[Terminal v2 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/terminal-v2-roadmap.md
|
||||
[Terminal v2 Roadmap]: ./terminal-v2-roadmap.md
|
||||
|
||||
[Windows Terminal Preview 1.2 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-2-release/
|
||||
[Windows Terminal Preview 1.3 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-3-release/
|
||||
@@ -126,3 +130,5 @@ Incoming issues/asks/etc. are triaged several times a week, labeled appropriatel
|
||||
[Windows Terminal Preview 1.12 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-12-release/
|
||||
[Windows Terminal Preview 1.13 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-13-release/
|
||||
[Windows Terminal Preview 1.14 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-14-release/
|
||||
|
||||
[Terminal 2023 Roadmap]: ./roadmap-2023.md
|
||||
|
||||
76
doc/roadmap-2023.md
Normal file
76
doc/roadmap-2023.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Terminal 2023 Roadmap
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the roadmap of features we're planning for the Windows Terminal during 2023. This serves as a successor to the [2022 Roadmap], to reflect changes to our planning going forward.
|
||||
|
||||
## Release cadence
|
||||
|
||||
We've settled on a roughly quarterly release cycle - about once every three months. In May we released [Terminal 1.18]. We're targeting 1.19 for sometime in late September, and 1.20 likely in early January 2024. (These timelines are rough estimates, not strict rules. For example, 1.18's release was pushed back slightly to better align with Build 2023.)
|
||||
|
||||
New features will go into [Windows Terminal Preview](https://aka.ms/terminal-preview) first. Typically, one release after they've been in Preview, those features will move into [Windows Terminal](https://aka.ms/terminal) ("Terminal Stable"). In the case of some more risky or experimental features, we might hold them to only Preview builds for an extended period[^1].
|
||||
|
||||
|
||||
| Quarter | Date | Release Version | Preview Release Blog Post |
|
||||
| --------|------------|---------------- | ------------------------- |
|
||||
| CY23 Q1 | 2023-01-24 | [Terminal 1.17] | [Windows Terminal Preview 1.17 Release] |
|
||||
| CY23 Q2 | 2023-05-23 | [Terminal 1.18] | [Windows Terminal Preview 1.18 Release] |
|
||||
| CY23 Q3 | | [Terminal 1.19] | [Windows Terminal Preview 1.19 Release] |
|
||||
| CY23 Q4 | | [Terminal 1.20] | [Windows Terminal Preview 1.20 Release] |
|
||||
|
||||
Within a single milestone, we typically reserve the last month as "bake time", to polish off bugfixes and get the release ready to ship. In this last month, we'll likely slow down our ingestion of community PRs just to stabilize what's already in `main`. For example, a given release might look like:
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title Proposed Terminal Releases 1.14-1.18
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d %b
|
||||
section Terminal 1.18
|
||||
Lock down & bake :l18, 2023-05-09 , 2w
|
||||
Release 1.18 :milestone, 2023-05-23, 0
|
||||
1.18 becomes Stable :milestone, after l19, 0
|
||||
section Terminal 1.19
|
||||
Features :f19, after l18, 10w
|
||||
Bugfix :b19, after f19 , 4w
|
||||
Lock down & bake :l19, after b19 , 2w
|
||||
Release 1.19 :milestone, after l19, 0
|
||||
```
|
||||
|
||||
_informative, not normative_
|
||||
|
||||
## Up next in the Terminal
|
||||
|
||||
### Terminal 1.19
|
||||
|
||||
* Canary builds. Nightly builds of the Terminal from `main`. More unstable, but quicker access to experimental features.
|
||||
* Terminal AI. While this will only be shipping in Canary builds to begin with, the v0 implementation will be available roughly at the same time as 1.19.
|
||||
* The Suggestions UI. This is the starting point for shell completions [#3121], tasks [#1595], and probably Terminal AI at some point too.
|
||||
* Unicode input for `cmd.exe` (and any other console app using "cooked reads"). See [#15567]
|
||||
* Miscellaneous performance improvements. Conhost should be a _lot_ faster now.
|
||||
* Broadcast input mode, for sending text to multiple panes at once.
|
||||
|
||||
## Team member "north stars"
|
||||
|
||||
For a more fluid take on what each of the team's personal goals are, head on over to [Core team North Stars]. This has a list of more long-term goals that each team member is working towards, but not things that are necessarily committed work.
|
||||
|
||||
|
||||
[^1]: A conclusive list of these features can be found at [../src/features.xml](../src/features.xml). Note that this is a raw XML doc used to light up specific parts of the codebase, and not something authored for human consumption.
|
||||
|
||||
[2022 Roadmap]: ./roadmap-2022.md
|
||||
|
||||
[Terminal 1.17]: https://github.com/microsoft/terminal/releases/tag/v1.17.1023
|
||||
[Terminal 1.18]: https://github.com/microsoft/terminal/releases/tag/v1.18.1462.0
|
||||
[Windows Terminal Preview 1.17 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-17-release/
|
||||
[Windows Terminal Preview 1.18 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-18-release/
|
||||
|
||||
[@DHowett]: https://github.com/DHowett
|
||||
[@zadjii-msft]: https://github.com/zadjii-msft
|
||||
[@lhecker]: https://github.com/lhecker
|
||||
[@carlos-zamora]: https://github.com/carlos-zamora
|
||||
[@PankajBhojwani]: https://github.com/PankajBhojwani
|
||||
|
||||
[Core team North Stars]: https://github.com/microsoft/terminal/wiki/Core-team-North-Stars
|
||||
|
||||
[#1595]: https://github.com/microsoft/terminal/issues/1595
|
||||
[#3121]: https://github.com/microsoft/terminal/issues/3121
|
||||
[#15567]: https://github.com/microsoft/terminal/issues/15567
|
||||
@@ -435,7 +435,7 @@ ultimately deemed it to be out of scope for the initial spec review.
|
||||
|
||||
<!-- 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
|
||||
[Command Palette, Addendum 1]: ../%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
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 585 KiB |
744
doc/specs/#1595 - Suggestions UI/Suggestions-UI.md
Normal file
744
doc/specs/#1595 - Suggestions UI/Suggestions-UI.md
Normal file
@@ -0,0 +1,744 @@
|
||||
---
|
||||
author: Mike Griese
|
||||
created on: 2022-08-22
|
||||
last updated: 2023-08-03
|
||||
issue id: 1595
|
||||
---
|
||||
|
||||
# Windows Terminal - Suggestions UI
|
||||
|
||||
## Abstract
|
||||
|
||||
Multiple related scenarios have come up where it would be beneficial to display
|
||||
actionable UI to the user within the context of the active terminal itself. This
|
||||
UI would be akin to the Intellisense UI in Visual Studio. It appears right where
|
||||
the user is typing, and can help provide immediate content for the user, based
|
||||
on some context. The "Suggestions UI" is this new ephemeral UI within the
|
||||
Windows Terminal that can display different types of actions, from different
|
||||
sources.
|
||||
|
||||
## Background
|
||||
|
||||
The Suggestions UI is the singular UI by which the Terminal can display a
|
||||
variety of suggestions to the user. These include:
|
||||
|
||||
* Recent commands the user has executed in this terminal, powered by shell integration.
|
||||
* Recent directories, similarly powered by shell integration
|
||||
* Completions from the shell itself (like the shell completions in PowerShell)
|
||||
* Tasks, which are `sendInput` actions from the user's settings
|
||||
* Buffer Completions, which is a dumb type of autocomplete based on words in the buffer
|
||||
* and more (as provided via extensions)
|
||||
|
||||
All of these scenarios are places where it makes sense to present the user a
|
||||
menu at the point of text insertion in the terminal control itself.
|
||||
|
||||
### Inspiration
|
||||
|
||||
Primarily, the inspiration is any Intellisense-like experience, in any app.
|
||||
Visual Studio, VsCode, PowerShell, vim, Sublime any JetBrains IDE - there's more
|
||||
than enough examples in the wild.
|
||||
|
||||
Ultimately, the inspiration for the Suggestions UI came from a bunch of places
|
||||
all at once. In the course of a few months though, it became clear that we'd
|
||||
need a unified UI for displaying a variety of suggestion-like experiences in the
|
||||
Terminal. Our work with the PowerShell and VsCode teams helped refine these
|
||||
requests all into the unified design below.
|
||||
|
||||
### User Stories
|
||||
|
||||
Size | Description
|
||||
-----------|--
|
||||
🐣 Crawl | The user can bring up the Suggestions UI with recent commands, powered by shell integration
|
||||
🐣 Crawl | [#12863] The user can bring up the Suggestions UI with recent directories, powered by shell integration
|
||||
🚶 Walk | The user can bring up the Suggestions UI with tasks from their settings
|
||||
🚶 Walk | CLI apps can invoke the Suggestions UI with a new VT sequence
|
||||
🚶 Walk | The Suggestions UI can be opened using the current typed commandline as a filter
|
||||
🚶 Walk | Recent commands and directories are stored in `state.json`, across sessions
|
||||
🏃♂️ Run | Suggestions can have descriptions presented in / alongside the UI
|
||||
🏃♂️ Run | The Suggestions UI can be opened without any nesting
|
||||
🏃♂️ Run | The Suggestions UI can be opened, nested by `source` of the suggestion
|
||||
🚀 Sprint | Extensions can provide suggestion sources for the Suggestions UI
|
||||
🚀 Sprint | The Suggestions UI can be opened in "inline" mode, only showing the text of the first suggestion
|
||||
|
||||
### Elevator Pitch
|
||||
|
||||
The Suggestions UI is a UI element displayed in the Terminal for providing
|
||||
different types of text suggestions to the user - anything from recently run
|
||||
commands, to saved commands, to tab-completion suggestions from the shell
|
||||
itself.
|
||||
|
||||
## Business Justification
|
||||
|
||||
It will delight developers.
|
||||
|
||||
Furthermore, our partners on the Visual Studio team have been requesting similar
|
||||
functionality for some time now. The way autocompletion menus in PowerShell
|
||||
currently interact with UIA clients leaves much to be desired. They'd like a way
|
||||
to provide richer context to screen readers. Something to enable the terminal to
|
||||
more specifically describe the context of what's being presented to the user.
|
||||
|
||||
## Scenario Details
|
||||
|
||||
### UI/UX Design
|
||||
|
||||
#### Prototypes
|
||||
|
||||
The following gif was a VsCode prototype of [shell-driven autocompletion]. This
|
||||
is the point of reference we're starting from when talking about what the
|
||||
suggestions UI might look like.
|
||||
|
||||

|
||||
|
||||
These suggestions are populated by logic within PowerShell itself, and
|
||||
communicated to the Terminal. The Terminal can then display them in the
|
||||
Suggestions UI.
|
||||
|
||||
The following demonstrate a prototype of what that might look like for the
|
||||
Terminal. These are meant to be informative, not normative, representations of
|
||||
what the UI would look like.
|
||||
|
||||

|
||||
|
||||
A prototype of the recent commands UI, powered by shell integration:
|
||||
|
||||

|
||||
|
||||
A prototype of the tasks UI, powered by the user's settings:
|
||||
|
||||

|
||||
|
||||
(admittedly, the `TeachingTip` in that gif is a prototype and was later replaced
|
||||
with a better version.)
|
||||
|
||||
In general, the Suggestions UI will present a list of elements to select from,
|
||||
near the text cursor. This control might be contain a text box for filtering
|
||||
these items (a "**palette**"), or it might not (a "**menu**").
|
||||
|
||||

|
||||
|
||||
#### Palette vs Menu
|
||||
|
||||
Depending on how the suggestions UI is invoked, we may or may not want to
|
||||
display a text box for filtering these suggestions. Consider the Intellisense
|
||||
menu in Visual Studio. That's a UI that only allows for up/down for navigation
|
||||
(and enter/tab for selecting the suggestion).
|
||||
|
||||
For suggestions driven by the Terminal, we'll display a filtering text box in
|
||||
the Suggestions UI. This is similar to the command palette's search - a fuzzy
|
||||
search to filter the contents. This is the "**palette**" style of the
|
||||
suggestions dialog.
|
||||
|
||||
For completions driven by the shell, we should probably not display the
|
||||
filtering text box. This is the "**menu**" style of the suggestion dialog. The
|
||||
user is primarily interacting with the shell here, not the Terminal.
|
||||
|
||||
> **Warning**
|
||||
> TODO! For discussion, possibly with a real UX designer.
|
||||
|
||||
How should we handle completions here? Tab? Enter? Right-Arrow? Should we have
|
||||
an element selected when we open the menu, or should tab/enter only work once
|
||||
the user has used the arrows at least once? Sublime allows for <kbd>tab</kbd> to
|
||||
complete the suggestion immediately.
|
||||
|
||||
Consider also that these suggestions might be provided by the shell, as the user
|
||||
is typing at a commandline shell. For something like PowerShell, the user might
|
||||
want to start typing a command and have it tab-complete based off the shell's
|
||||
tab expansion rules. PowerShell's inline suggestions use right-arrow to
|
||||
differentiate "use this suggestion" vs tab for "tab expand what I'm typing at
|
||||
the prompt". We should probably preserve this behavior.
|
||||
|
||||
We probably don't want to provide different experiences for the **menu** version
|
||||
of the Suggestions UI vs. the **palette** version. In the palette version, the
|
||||
user won't be pressing tab to tab-complete at the shell - the focus is out of
|
||||
the of terminal and in the Suggestions UI. With the menu version, the focus is
|
||||
still "in the terminal", and users would expect tab to tab-complete.
|
||||
|
||||
We will want to make sure that there's some semblance of consistency across our
|
||||
implementation for the Suggestions UI, our own Command Palette, VsCode's
|
||||
intellisense and their own implementation of shell-completions in the Terminal.
|
||||
|
||||
> **Note**
|
||||
> In my prototype, for the "Menu" mode, I accepted ALL of right-arrow, tab, and
|
||||
> enter as "accept completion", and any other key dismissed the UI. This _felt_
|
||||
> right for that mode. I'm not sure we could make the same call for "palette"
|
||||
> mode, where we'd need tab for navigating focus.
|
||||
|
||||
### Implementation Details
|
||||
|
||||
#### Fork the Command Palette
|
||||
|
||||
We're largely going to start with the Command Palette to build the Suggestions
|
||||
UI[[1](#footnote-1)]. The Command Palette is already a control we've built for displaying a
|
||||
transient list of commands and dispatching them to the rest of the app.
|
||||
|
||||
Currently, the Command Palette is a single static control, at the top-center of
|
||||
the Terminal window, and occupying a decent portion of the screen. For the
|
||||
Suggestions UI, we'll instead want to make sure that the control appears
|
||||
relative to the current cursor position.
|
||||
|
||||
We'll start by taking the command palette, and copying it over to a new control.
|
||||
This will allow us to remove large chunks of code dealing with different modes
|
||||
(i.e. the tab switcher), and code dealing with prefix characters to switch
|
||||
modes.
|
||||
|
||||
We'll need to make some small modifications to enable the Suggestions UI to
|
||||
* work as a text cursor-relative control
|
||||
* exist as a Flyout outside the bounds of the Terminal window
|
||||
* If the Suggestions UI is too close to the bottom of the screen, we'll need it to open
|
||||
"upwards", with the search box at the _bottom_ and the list extending above it
|
||||
* prevent it from switching to command-line mode
|
||||
* display tooltips / `TeachingTip`s / some secondary flyout with a description
|
||||
of the suggestion (if provided)
|
||||
|
||||
#### Completion sources
|
||||
|
||||
The Suggestions UI will support suggestions from a variety of different
|
||||
"sources". As an example, consider the following actions:
|
||||
|
||||
```json
|
||||
{ "command": { "action":"suggestions", "source": "commandHistory" } },
|
||||
{ "command": { "action":"suggestions", "source": "directoryHistory" } },
|
||||
|
||||
{ "command": { "action":"suggestions", "source": "tasks" } },
|
||||
{ "command": { "action":"suggestions", "source": "local" } },
|
||||
|
||||
{ "command": { "action":"suggestions", "source": ["local", "tasks", "commandHistory"] } },
|
||||
|
||||
{ "command": { "action":"suggestions", "source": "Microsoft.Terminal.Extensions.BufferComplete" } },
|
||||
```
|
||||
|
||||
Each of these `suggestions` actions would open the Suggestions UI with a
|
||||
different set of actions.
|
||||
|
||||
* `commandHistory`: Use commands from this session, as identified via shell
|
||||
integration. This won't be able to return any suggestions if the user has not
|
||||
configured their shell to support shell integration sequences yet.
|
||||
* `directoryHistory`: Populate the list with a series of `cd {path}` commands,
|
||||
where the paths are populated via shell integration. Paths are in MRU order.
|
||||
* `tasks`: Populate the list with all `sendInput` actions in the user's settings
|
||||
file. The command structure should remain unchanged. For example, if they have
|
||||
`sendInput` actions nested under a "git" command, then the "git" entry will
|
||||
remain in this tasks view with their `sendInput` actions nested inside it. For
|
||||
more details, see the [Tasks] spec.
|
||||
* `local`: Populate the list with tasks that are located in the CWD, in a file
|
||||
named `.wt.json`. For more details, see the [Tasks] spec.
|
||||
* `Microsoft.Terminal.Extensions.BufferComplete`: As an example, this
|
||||
demonstrates how an action might be authored to reference a suggestion source
|
||||
from an extension[[2](#footnote-2)].
|
||||
|
||||
Each of these different sources will build a different set of `Command`s,
|
||||
primarily populated with `sendInput` actions. We'll load those `Command`s into
|
||||
the Suggestions UI control, and open it at the text cursor.
|
||||
|
||||
To drill in on a single example - the `commandHistory` source. In that
|
||||
particular case, the TerminalPage will query the active TermControl for a list
|
||||
of its recent commands. If it knows these (via shell integration), then the
|
||||
TerminalPage will use that list of commands to build a list of `sendInput`
|
||||
actions. Those will then get fed to the suggestions UI.
|
||||
|
||||
Not listed above is [shell-driven autocompletion]. These aren't something that
|
||||
the Terminal can invoke all on its own - these are something the shell would
|
||||
need to invoke themselves.
|
||||
|
||||
#### Pre-populate the current commandline context
|
||||
|
||||
Consider the following scenario. A user has typed `git c` in their shell, and
|
||||
has [shell integration] enabled for their shell. They want to open the
|
||||
Suggestions UI filtered to their recent history, but starting with what they've
|
||||
already typed. To support this scenario, we'll add an additional property:
|
||||
|
||||
* `"useCommandline"`: `bool` (**default**: `true`)
|
||||
* `true`: the current commandline the user has typed will pre-populate the
|
||||
filter of the Suggestions UI. This requires that the user has enabled shell
|
||||
integration in their shell's config.
|
||||
* `false`: the filter will start empty, regardless of what the user has typed.
|
||||
|
||||
With that setting, the user can achieve their desired UX with the following action:
|
||||
|
||||
```json
|
||||
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true } },
|
||||
```
|
||||
|
||||
Now, when they type `git c` and invoke the Suggestions UI, they can immediately
|
||||
start searching for recent commands that started with `git c`.
|
||||
|
||||
The primary use case for `useCommandline: false` was for `"nesting": "source"`.
|
||||
When filtering a list of ["Tasks...", "Recent commands...", "Recent
|
||||
directories...", "Docker...", "Git..."], then there's minimal value to start by
|
||||
filtering to "git c".
|
||||
|
||||
#### Default actions
|
||||
|
||||
I propose adding the following actions to the Terminal by default:
|
||||
|
||||
```json
|
||||
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true } },
|
||||
{ "command": { "action":"suggestions", "source": "directoryHistory" } },
|
||||
{ "command": { "action":"suggestions", "source": ["local", "tasks", "commandHistory"], "useCommandline": true, "nesting": "disabled" } },
|
||||
{ "command": { "action":"suggestions", "source": ["all"], "useCommandline": false, "nesting": "source" } },
|
||||
```
|
||||
|
||||
These actions are colloquially:
|
||||
* Give me suggestions from my recent commands, using what I've typed
|
||||
* Give me suggestions of directories I've recently been in
|
||||
* _(After [Tasks] are implemented)_ Give me suggestions from recent commands,
|
||||
commands I've saved, and commands for this project. Don't nest any, so they're
|
||||
all in the top-level menu. Use what I've typed already to start filtering.
|
||||
* Just open the Suggestions UI with all suggestions sources, and group them by
|
||||
the source of the suggestions.
|
||||
|
||||
This should cover most of the basic use cases for suggestions.
|
||||
|
||||
#### Who owns this menu?
|
||||
|
||||
There was some discussion of who should own the suggestions menu. The control
|
||||
itself? Or the app hosting the control?
|
||||
|
||||
A main argument for hosting this UI in the control itself is that any consumer
|
||||
of the `TermControl` should be able to display the [shell-driven autocompletion]
|
||||
menu. And they should get the UI from us "for free". Consumers shouldn't need to
|
||||
reimplement it themselves. This probably could be done without many changes:
|
||||
* Instead of operating on `Command`s and actions from the terminal settings,
|
||||
the control could just know that all the entries in the menu are "send
|
||||
input" "actions".
|
||||
* The control could offer a method to manually invoke the Suggestions UI for a
|
||||
list of {suggestion, name, description} objects.
|
||||
* The app layer could easily translate between sendInput actions and these
|
||||
pseudo-actions.
|
||||
|
||||
A big argument in favor of having the app layer host the control: Consider an
|
||||
app like Visual Studio. When they embed the control, they'll want to style the
|
||||
shell-completions UI in their own way. They already have their own intellisense
|
||||
menu, and their own UI paradigm.
|
||||
|
||||
For now, we'll leave this as something that's owned by the app layer. When we
|
||||
get around to finalizing the [shell-driven autocompletion] design, we can
|
||||
iterate on ideas for supporting both consumers that want to use a pre-built
|
||||
suggestions control, or consumers who want to bring their own.
|
||||
|
||||
## Tenets
|
||||
|
||||
<table>
|
||||
|
||||
<tr><td><strong>Compatibility</strong></td><td>
|
||||
|
||||
This shouldn't break any existing flows. This is a general purpose UI element,
|
||||
to be extended in a variety of ways. Those customizations will all be opt-in by
|
||||
the user, so I'm not expecting any breaking compatibility changes here.
|
||||
|
||||
</td></tr>
|
||||
|
||||
<tr><td><strong>Accessibility</strong></td><td>
|
||||
|
||||
The Suggestions UI was designed with the goal of making commandline shell
|
||||
suggestions _more_ accessible. As Carlos previously wrote:
|
||||
|
||||
> Screen readers struggle with this because the entire menu is redrawn every time, making it harder to understand what exactly is "selected" (as the concept of selection in this instance is a shell-side concept represented by visual manipulation).
|
||||
>
|
||||
> ...
|
||||
>
|
||||
> _\[Shell driven suggestions\]_ can then be leveraged by Windows Terminal to create UI elements. Doing so leverages WinUI's accessible design.
|
||||
|
||||
This will allow the Terminal to provide more context-relevant information to
|
||||
screen readers.
|
||||
|
||||
</td></tr>
|
||||
|
||||
<tr><td><strong>Sustainability</strong></td><td>
|
||||
|
||||
No sustainability changes expected.
|
||||
|
||||
</td></tr>
|
||||
|
||||
<tr><td><strong>Localization</strong></td><td>
|
||||
|
||||
The localization needs of the Suggestions UI will be effectively the same as the
|
||||
needs of the Command Palette.
|
||||
|
||||
The Terminal will have no way to localize suggestions that are provided via
|
||||
[shell-driven autocompletion]. These are just verbatim strings that the shell
|
||||
told us to use. We don't consider this to be something to worry about, however.
|
||||
This is no different than the fact that Terminal cannot localize the `Get-Help`
|
||||
(or any other) output of PowerShell.
|
||||
|
||||
</td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
This is more of an informative outline, rather than a normative one. Many of the
|
||||
things from Crawl, Walk, and Run are all already in PRs as of the time of this
|
||||
spec's review.
|
||||
|
||||
### 🐣 Crawl
|
||||
|
||||
* [ ] Fork the Command palette to a new UI element, the `SuggestionsControl`
|
||||
* [ ] Enable previewing `sendInput` actions in the Command Palette and `SuggestionsControl`
|
||||
* [ ] Enable the `SuggestionsControl` to open top-down (aligned to the bottom of the cursor row) or bottom-up (aligned to the top of the cursor row).
|
||||
* [ ] Disable sorting on the `SuggestionsControl` - elements should presumably be pre-sorted by the source.
|
||||
* [ ] Expose the recent commands as a accessor on `TermControl`
|
||||
* [ ] Add a `suggestions` action which accepts a single option `recentCommands`. These should be fed in MRU order to the `SuggestionsControl`.
|
||||
* [ ] Expose the recent directories as an accessor on `TermControl`, and add a `recentDirectories` source.
|
||||
|
||||
### 🚶 Walk
|
||||
|
||||
* [ ] Add a `tasks` source to `suggestions` which opens the Suggestions UI with
|
||||
a tree of all `sendInput` commands
|
||||
* [ ] Enable the `SuggestionsControl` to open with or without a search box
|
||||
* [ ] Plumb support for shell-driven completions through the core up to the app
|
||||
* [ ] Expose the _current_ commandline from the `TermControl`
|
||||
* [ ] Add a `useCommandline` property to `suggestions`, to pre-populate the search with the current commandline.
|
||||
* [ ] Persist recent commands / directories accordingly
|
||||
|
||||
### 🏃♂️ Run
|
||||
|
||||
* [ ] Add a `description` field to `Command`
|
||||
* [ ] Add a `TeachingTip` (or similar) to the Suggestions UI to display
|
||||
descriptions (when available)
|
||||
* [ ] Use the `ToolTip` property of shell-driven suggestions as the description
|
||||
* [ ] Add a boolean `nesting` property which can be used to disable nesting on the `tasks` source.
|
||||
* [ ] Add the ability for `nesting` to accept `enabled`/`disabled` as `true`/`false` equivalents
|
||||
* [ ] Add the ability for `nesting` to accept `source`, which instead groups all
|
||||
commands to the Suggestions UI by the source of that suggestion.
|
||||
|
||||
### 🚀 Sprint
|
||||
|
||||
The two "sprint" tasks here are much more ambitious than the other listed
|
||||
scenarios, so breaking them down to atomic tasks sees less reasonable. We'd have
|
||||
to spend a considerable amount more time figuring out _how_ to do each of these
|
||||
first.
|
||||
|
||||
For example - extensions. We have yet to fully realize what extensions _are_.
|
||||
Determining how extensions will provide suggestions is left as something we'll
|
||||
need to do as a part of the Extensions spec.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Here's a sample json schema for the settings discussed here.
|
||||
|
||||
```json
|
||||
"OpenSuggestionsAction": {
|
||||
"description": "Arguments corresponding to a Open Suggestions Action",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "suggestions"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/$defs/SuggestionSource",
|
||||
"description": "Which suggestion sources to filter."
|
||||
},
|
||||
"useCommandline": {
|
||||
"default": false,
|
||||
"description": "When set to `true`, the current commandline the user has typed will pre-populate the filter of the Suggestions UI. This requires that the user has enabled shell integration in their shell's config. When set to false, the filter will start empty."
|
||||
},
|
||||
"nesting": {
|
||||
"default": true,
|
||||
"description": "When set to `true`, suggestions will follow the provided nesting structure. For Tasks, these will follow the structure of the Command Palette. When set to `false`, no nesting will be used (and all suggestions will be in the top-level menu.",
|
||||
"$comment": "This setting is a possible follow-up setting, not required for v1. "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"BuiltinSuggestionSource": {
|
||||
"enum": [
|
||||
"commandHistory",
|
||||
"directoryHistory",
|
||||
"tasks",
|
||||
"local",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SuggestionSource": {
|
||||
"default": "all",
|
||||
"description": "Either a single suggestion source, or an array of sources to concatenate. Built-in sources include `commandHistory`, `directoryHistory`, `tasks`, and `local`. Extensions may provide additional values. The special value `all` indicates all suggestion sources should be included",
|
||||
"$comment": "`tasks` and `local` are sources that would be added by the Tasks feature, as a follow-up"
|
||||
"oneOf": [
|
||||
{
|
||||
"type": [ "string", "null", "BuiltinSuggestionSource" ]
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": { "type": "BuiltinSuggestionSource" }
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
|
||||
### Future Considerations
|
||||
|
||||
* Another extension idea: `WithFig.FigCompletions`. Imagine an extension that
|
||||
could parse existing [Fig] completion specs, and provide those as suggestions
|
||||
in this way.
|
||||
* This might be a good example of an async suggestion source. The current
|
||||
commandline is used as the starting filter, and the suggestions would be
|
||||
populated by some `fig` process / thread / async operation that returns the
|
||||
suggestions.
|
||||
* If the user hasn't enabled shell completion, we could add text to the
|
||||
`commandHistory` or `directoryHistory` menus to inform the user how they could
|
||||
go enable shell integration. We already have a docs page dedicated to this, so
|
||||
we could start by linking to that page. More notes on this in [Automatic shell
|
||||
integration](#Automatic-shell-integration).
|
||||
* Maybe there could be a per-profile setting for automatic suggestions after
|
||||
some timeout. Like, as you type, a menu version of the Suggestions UI appears.
|
||||
So you could just start typing `git c`, and it would automatically give you a
|
||||
menu with suggestions, implicitly using the typed command as the "filter".
|
||||
* Maybe we could do this as an `implicit` property on the `suggestions` action
|
||||
|
||||
|
||||
#### Description Tooltips
|
||||
|
||||
> **Note**: _This is left as a future consideration for the initial draft of
|
||||
> this spec. I'd like to flesh out [shell-driven autocompletion] more before
|
||||
> committing any plans here._
|
||||
|
||||
It would be beneficial for the Suggestions UI to display additional context to
|
||||
the user. Consider a extension that provides some commands for the user, like a
|
||||
hypothetical "Docker" extension. The extension author might be able to give the
|
||||
commands simplified names, but also want to expose a more detailed description
|
||||
of the commands to the user.
|
||||
|
||||
Or consider the Suggestions UI when invoked by [shell-driven autocompletion].
|
||||
The shell might want to provide help text to the user with each of the
|
||||
suggestions. This would allow a user to browse through the suggestions that they
|
||||
might not know about, and learn how they work before committing to one.
|
||||
|
||||
Only the help text for the currently hovered command should be presented to the
|
||||
user. To support this kind of UX, we'll add an optional flyout of some sort to
|
||||
display with the Suggestions UI. This flyout will only appear if there's more
|
||||
information provided to the Terminal.
|
||||
|
||||
This might be in the form of a `TeachingTip`, as in this example:
|
||||
|
||||

|
||||
|
||||
Actions in the settings could also accept an optional `description` property, to
|
||||
specify the string that would be presented in that flyout.
|
||||
|
||||
#### Automatic shell integration
|
||||
|
||||
A large portion of these features all rely on shell integration being enabled by
|
||||
the user. However, this is not a trivial thing for the Terminal to do on behalf
|
||||
of the user. Shell integration relies on changes to the user's shell config. If
|
||||
the Terminal were to try and configure those itself, we may accidentally destroy
|
||||
configuration that the user has already set up. Hence why the Terminal can't
|
||||
just have a "Light up all the bells and whistles" toggle in the Settings UI.
|
||||
|
||||
This is a non-trivial problem to solve, so it is being left as a future
|
||||
consideration, for a later spec. It deserves its own spec to sort out how we
|
||||
should expose this to users and safely implement it.
|
||||
|
||||
#### Pre-filtering the UI & filter by source
|
||||
|
||||
> **Note**: _This is a brainstorm I considered while writing this spec. I would
|
||||
> not include it in the v1 of this spec. Rather, I'd like to leave it for
|
||||
> where we might go with this UX in the future._
|
||||
|
||||
Do want to support different _types_ of nesting? So instead of just the default,
|
||||
there could be something like `nesting: "source"`, to create a menu structured
|
||||
like:
|
||||
|
||||
```
|
||||
Suggestions UI
|
||||
├─ Recent Commands...
|
||||
│ ├─ git checkout main
|
||||
│ ├─ git fetch
|
||||
│ └─ git pull
|
||||
├─ Recent Directories...
|
||||
│ ├─ d:\dev
|
||||
│ ├─ d:\dev\public
|
||||
│ └─ d:\dev\public\terminal
|
||||
├─ Saved tasks...
|
||||
│ ├─ Git...
|
||||
│ │ └─ git commit -m "
|
||||
│ │ └─ git log...
|
||||
│ └─ bx & runut
|
||||
└─ Docker
|
||||
├─ docker build --platform linux/amd64 <path>
|
||||
└─ docker logs -f --tail <lines_count> <container_name>
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> I'm using `Docker` as an example fragment extension that provides
|
||||
> some `docker` commands. When grouping by `"source"`, we could pull those into
|
||||
> a separate top-level entry. When not grouping by `"source"`, those would still
|
||||
> show up with the rest of `tasks`. )
|
||||
|
||||
#### Store recent commands across sessions
|
||||
|
||||
> **Note**
|
||||
> _I'm not sure we really want to put this in this spec or not, hence
|
||||
> why it is in the "Future considerations" section. I think it is worth
|
||||
> mentioning. This might be better served in the [shell integration] doc._
|
||||
|
||||
We'll probably want a way for recent commands to be saved across sessions. That way, your `cmd.exe` command history could persist across sessions. We'd need:
|
||||
|
||||
* A setting to enable this behavior
|
||||
* A setting to control the context of these saved commandlines.
|
||||
* Do we want them saved per-profile, or globally?
|
||||
* If they're saved per-profile, maybe a profile can opt-in to loading all the commands?
|
||||
* How does defterm play with this? Do we "layer" by concatenating per-profile commands with `profiles.defaults` ones?
|
||||
* A button in the Settings UI for clearing these commands
|
||||
* Should fragments be able to pre-populate "recent commands"?
|
||||
* I'm just gonna say _no_. That would be a better idea for Tasks (aka just a `sendInput` Action that we load from the fragment normally as a Task), or a specific suggestion source for the fragment extension.
|
||||
|
||||
#### Inline mode
|
||||
|
||||
> **Note**
|
||||
> _This is a half-baked idea with some potential. However, I don't
|
||||
> think it needs to be a part of the v1 of the Suggestions UI, so I'm leaving it
|
||||
> under future considerations for a future revision._
|
||||
|
||||
Do we want to have a suggestions UI "mode", that's just **one** inline
|
||||
suggestion, "no" UI? Some UX ala the `PsReadline` recent command suggestion
|
||||
feature. Imagine, we just display the IME ghost text thing for the first result,
|
||||
given the current prompt?
|
||||
|
||||
Take the following action as an example:
|
||||
|
||||
```json
|
||||
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true, "inline": true } },
|
||||
```
|
||||
|
||||
Type the start of some command at the prompt, and press that key. Presto, we do
|
||||
the `pwsh` thing. Ghost text appears for the first match in the `commandHistory`
|
||||
for what the user has typed. If they press another key, ~they've typed into the
|
||||
"hidden" Suggestions UI, which filters the (hidden) list more, and updates the
|
||||
one inline suggestion.~
|
||||
|
||||
Or, instead, typed keys go to the shell, and then we re-query the commandline,
|
||||
and update the filter accordingly. That would allow tab-completion to still
|
||||
work. We'd use <kbd>right arrow</kbd> to accept the suggestion (and dismiss the
|
||||
ghost text preview).
|
||||
|
||||
This would seemingly SUPER conflict with PowerShell's own handler. Probably not
|
||||
something someone should enable for PowerShell 7 profiles if they're using that
|
||||
feature.
|
||||
|
||||
### Rejected ideas
|
||||
|
||||
These are musings from earlier versions of the spec.
|
||||
* **Asynchronous prompting**: This was rejected because it was so fundamentally
|
||||
different from the rest of the UX of the Suggestions UI, it didn't make sense
|
||||
to try and also do that behavior.
|
||||
* ...
|
||||
|
||||
#### REJECTED: Asynchronous prompting
|
||||
|
||||
Certain suggestion sources might want to provide results asynchronously.
|
||||
Consider a source that might want to make a web request to populate what strings
|
||||
to suggest. That source might want to prompt the user for input first, then
|
||||
dispatch the request, then populate the UI. Or something like a `fig`-like
|
||||
suggestion source, which would need to parse some files from the disk to
|
||||
generate the list of suggestions.
|
||||
|
||||
The easiest way to do this would be to provide a secondary UI element for
|
||||
prompting the user for input, doing the request in the background, then opening
|
||||
the UI later. However, that feels a little disjointed. Could we instead provide
|
||||
a more continuous experience?
|
||||
|
||||
The following is a proposal for using the Suggestions UI itself as the control
|
||||
to prompt the user for input.
|
||||
|
||||
```c++
|
||||
TerminalPage::SetUpSuggestionsUI()
|
||||
{
|
||||
const auto& asyncSource{ AsyncSuggestions() };
|
||||
|
||||
suggestionsUI.OnInputChanged({ asyncSource, AsyncSuggestions::InputChangedHandler});
|
||||
// In this example, we don't want the UI to filter item based on the input
|
||||
// string - the source has already determined the list of relevant matches.
|
||||
suggestionsUI.FilterByInput(false);
|
||||
|
||||
asyncSource.SuggestionsChanged([](const auto& newCommands){
|
||||
suggestionsUI.Loading(false);
|
||||
suggestionsUI.Commands(newCommands);
|
||||
})
|
||||
}
|
||||
|
||||
void AsyncSuggestions::InputChangedHandler(FilterChangedArgs args)
|
||||
{
|
||||
// kick off a trailing ThrottledFunc to do a new query
|
||||
_loadNewResults->Run(args.NewInputText());
|
||||
// If we get another request, we might want to cancel the pending throttled
|
||||
// func entirely, and start the timeout fresh. Just so that we only make a
|
||||
// query for the final string they type.
|
||||
|
||||
args.RequestLoading(true); // pass a boolean back up in the args, so that
|
||||
// the Suggestions UI can clear out the current commands, and start displaying an
|
||||
// indeterminate progress wheel.
|
||||
}
|
||||
```
|
||||
|
||||
That would basically _have_ to be special cased for this source, at least for
|
||||
now. We could refactor that later to better deal with extensions.
|
||||
|
||||
Let's make sure this would work for something `fig`-like, where the "prompt" is
|
||||
literally the prompt, what the user has already typed at the commandline.
|
||||
|
||||
After some discussion:
|
||||
* How do we differentiate the prompting version of the Suggestions UI from the
|
||||
filtering version?
|
||||
* The prompting version _doesn't_ filter results
|
||||
* Async modes wouldn't work with sync ones at all. E.g. if you did `source:
|
||||
["tasks", "myAsyncSource"]`. It doesn't make sense to start with a list of
|
||||
`tasks`, then type, find no tasks, but then oh! the UI fills in some other
|
||||
suggestions too. That's weird.
|
||||
|
||||
## Resources
|
||||
|
||||
These are some other work streams that have a lot of tie-in to the Suggestions
|
||||
UI. These are all being spec'd at roughly the same time, so links may not be
|
||||
fully up to date.
|
||||
* [Shell integration]
|
||||
* [Shell-driven autocompletion]
|
||||
* [Tasks]
|
||||
|
||||
### Footnotes
|
||||
|
||||
<a name="footnote-1"><a>[1]: We've had discussion in the past ([#7285]) about
|
||||
possibly creating a more abstract "Live filtering list view" to replace the
|
||||
Command Palette. We could most certainly use that here too. We've decided to
|
||||
initially go with a fork for now.
|
||||
|
||||
<a name="footnote-2"><a>[2]: Obviously, we're not having a real discussion about
|
||||
extensions in this doc. This example is solely to show that there's room for
|
||||
extensions to work with the "source" property in this design. What the final
|
||||
shape of extensions will be is very much still to be determined.
|
||||
|
||||
|
||||
[Fig]: https://github.com/withfig/autocomplete
|
||||
[Warp]: https://www.warp.dev/
|
||||
[workflows]: https://docs.warp.dev/features/workflows
|
||||
[also working on workflows]: https://fig.io/user-manual/workflows
|
||||
[winget script]: https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
|
||||
[#1595]: https://github.com/microsoft/terminal/issues/1595
|
||||
[#7039]: https://github.com/microsoft/terminal/issues/7039
|
||||
[#3121]: https://github.com/microsoft/terminal/issues/3121
|
||||
[#10436]: https://github.com/microsoft/terminal/issues/10436
|
||||
[#12927]: https://github.com/microsoft/terminal/issues/12927
|
||||
[#12863]: https://github.com/microsoft/terminal/issues/12863
|
||||
[#7285]: https://github.com/microsoft/terminal/issues/7285
|
||||
[#14939]: https://github.com/microsoft/terminal/issues/7285
|
||||
|
||||
[#keep]: https://github.com/zadjii/keep
|
||||
[VsCode Tasks]: ../../../.vscode/tasks.json
|
||||
|
||||
<!-- Note: This is its own spec in progress, but for the time being #12862 will do -->
|
||||
[Tasks]: https://github.com/microsoft/terminal/issues/12862
|
||||
<!-- Note: This is just a link to the PR that introduced the shell integration spec -->
|
||||
[shell integration]: https://github.com/microsoft/terminal/pull/14792
|
||||
<!-- Note: If I ever write a spec for this, go ahead and replace this link -->
|
||||
[shell-driven autocompletion]: https://github.com/microsoft/terminal/issues/3121
|
||||
BIN
doc/specs/#1595 - Suggestions UI/command-history-suggestions.gif
Normal file
BIN
doc/specs/#1595 - Suggestions UI/command-history-suggestions.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 965 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
doc/specs/#1595 - Suggestions UI/tasks-suggestions.gif
Normal file
BIN
doc/specs/#1595 - Suggestions UI/tasks-suggestions.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
doc/specs/#1595 - Suggestions UI/vscode-shell-suggestions.gif
Normal file
BIN
doc/specs/#1595 - Suggestions UI/vscode-shell-suggestions.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 431 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/main/doc/specs/%232046%20-%20Command%20Palette.md
|
||||
[Command Palette Spec]: ./%232046%20-%20Command%20Palette.md
|
||||
|
||||
@@ -612,8 +612,8 @@ You could have a profile that layers on an existing profile, with elevated-speci
|
||||
[#8514]: https://github.com/microsoft/terminal/issues/8514
|
||||
[#10276]: https://github.com/microsoft/terminal/issues/10276
|
||||
|
||||
[Process Model 2.0 Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%235000%20-%20Process%20Model%202.0.md
|
||||
[Configuration object for profiles]: https://github.com/microsoft/terminal/blob/main/doc/specs/Configuration%20object%20for%20profiles.md
|
||||
[Session Management Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%234472%20-%20Windows%20Terminal%20Session%20Management.md
|
||||
[Process Model 2.0 Spec]: ../%235000%20-%20Process%20Model%202.0.md
|
||||
[Configuration object for profiles]: ../%233062%20-%20Appearance configuration object for profiles.md
|
||||
[Session Management Spec]: ./%234472%20-%20Windows%20Terminal%20Session%20Management.md
|
||||
[The Old New Thing: How can I launch an unelevated process from my elevated process, redux]: https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443
|
||||
[Workspace Trust]: https://code.visualstudio.com/docs/editor/workspace-trust
|
||||
|
||||
@@ -559,4 +559,4 @@ runtime.
|
||||
[Tab Tear-out in the community toolkit]: https://github.com/windows-toolkit/Sample-TabView-TearOff
|
||||
[Quake mode scenarios]: https://github.com/microsoft/terminal/issues/653#issuecomment-661370107
|
||||
[`ISwapChainPanelNative2::SetSwapChainHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/windows.ui.xaml.media.dxinterop/nf-windows-ui-xaml-media-dxinterop-iswapchainpanelnative2-setswapchainhandle
|
||||
[Process Model 2.0 Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
|
||||
[Process Model 2.0 Spec]: ./doc/specs/%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
|
||||
|
||||
@@ -730,7 +730,7 @@ user to differentiate between the two behaviors.
|
||||
[#5727]: https://github.com/microsoft/terminal/issues/5727
|
||||
[#9992]: https://github.com/microsoft/terminal/issues/9992
|
||||
|
||||
[Process Model 2.0 Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
|
||||
[Process Model 2.0 Spec]: ../%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
|
||||
[Quake 3 sample]: https://youtu.be/ZmR6HQbuHPA?t=27
|
||||
[`RegisterHotKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey
|
||||
[`dev/migrie/f/653-QUAKE-MODE`]: https://github.com/microsoft/terminal/tree/dev/migrie/f/653-QUAKE-MODE
|
||||
|
||||
@@ -215,8 +215,8 @@ actions manually.
|
||||
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
|
||||
[Command Palette Spec]: ./doc/specs/%232046%20-%20Command%20Palette.md
|
||||
[New Tab Menu Customization Spec]: ./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
|
||||
|
||||
@@ -290,7 +290,7 @@ though. **I recommend we ignore this for now, and leave this as a follow-up**.
|
||||
For reference, refer to the following from iTerm2:
|
||||

|
||||
|
||||
We don't have a menu bar like on MacOS, but we do have a tab context menu. We
|
||||
We don't have a menu bar like on macOS, but we do have a tab context menu. We
|
||||
could add these items as a nested entry under each tab. If we wanted to do this,
|
||||
we should also make sure to dynamically change the icon of the MenuItem to
|
||||
reflect the current broadcast state.
|
||||
|
||||
@@ -373,7 +373,7 @@ changes, or the active pane in a tab changes:
|
||||
`TabRowControl` to match.
|
||||
|
||||
The `tab.cornerRadius` might be a bit trickier to implement. Currently, there's
|
||||
not a XAML resource that controls this, nor is this something that's exposed by
|
||||
no XAML resource that controls this, nor is this something that's exposed by
|
||||
the TabView control. Fortunately, this is something that's exposed to us
|
||||
programmatically. We'll need to manually set that value on each `TabViewItem` as
|
||||
we create new tabs. When we reload settings, we'll need to make sure to come
|
||||
|
||||
@@ -142,4 +142,4 @@ Feature Notes:
|
||||
[#4472]: https://github.com/microsoft/terminal/issues/4472
|
||||
[#8048]: https://github.com/microsoft/terminal/pull/8048
|
||||
|
||||
[Terminal 2022 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/roadmap-2022.md
|
||||
[Terminal 2022 Roadmap]: ./roadmap-2022.md
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
#define HAVE_AVX512
|
||||
#endif
|
||||
|
||||
#if defined(X86_OR_X64)
|
||||
#if defined(X86_OR_X64) && !defined(_M_ARM64EC)
|
||||
/* MSVC compatible compilers (Windows) */
|
||||
#if defined(_MSC_VER)
|
||||
/* clang-cl (LLVM 10 from 2020) requires /arch:AVX2 or
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
#include "../../inc/conattrs.hpp"
|
||||
|
||||
static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR };
|
||||
static constexpr TextAttribute InvalidTextAttribute{ INVALID_COLOR, INVALID_COLOR, INVALID_COLOR };
|
||||
|
||||
// Routine Description:
|
||||
// - This is a fill-mode iterator for one particular wchar. It will repeat forever if fillLimit is 0.
|
||||
|
||||
@@ -152,11 +152,15 @@ til::CoordType CharToColumnMapper::GetTrailingColumnAt(ptrdiff_t offset) noexcep
|
||||
return col;
|
||||
}
|
||||
|
||||
// If given a pointer inside the ROW's text buffer, this function will return the corresponding column.
|
||||
// This function in particular returns the glyph's first column.
|
||||
til::CoordType CharToColumnMapper::GetLeadingColumnAt(const wchar_t* str) noexcept
|
||||
{
|
||||
return GetLeadingColumnAt(str - _chars);
|
||||
}
|
||||
|
||||
// If given a pointer inside the ROW's text buffer, this function will return the corresponding column.
|
||||
// This function in particular returns the glyph's last column (this matters for wide glyphs).
|
||||
til::CoordType CharToColumnMapper::GetTrailingColumnAt(const wchar_t* str) noexcept
|
||||
{
|
||||
return GetTrailingColumnAt(str - _chars);
|
||||
@@ -364,11 +368,16 @@ void ROW::TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& a
|
||||
|
||||
void ROW::CopyFrom(const ROW& source)
|
||||
{
|
||||
RowCopyTextFromState state{ .source = source };
|
||||
CopyTextFrom(state);
|
||||
TransferAttributes(source.Attributes(), _columnCount);
|
||||
_lineRendition = source._lineRendition;
|
||||
_wrapForced = source._wrapForced;
|
||||
|
||||
RowCopyTextFromState state{
|
||||
.source = source,
|
||||
.sourceColumnLimit = source.GetReadableColumnCount(),
|
||||
};
|
||||
CopyTextFrom(state);
|
||||
|
||||
TransferAttributes(source.Attributes(), _columnCount);
|
||||
}
|
||||
|
||||
// Returns the previous possible cursor position, preceding the given column.
|
||||
@@ -382,7 +391,17 @@ til::CoordType ROW::NavigateToPrevious(til::CoordType column) const noexcept
|
||||
// Returns the row width if column is beyond the width of the row.
|
||||
til::CoordType ROW::NavigateToNext(til::CoordType column) const noexcept
|
||||
{
|
||||
return _adjustForward(_clampedColumn(column + 1));
|
||||
return _adjustForward(_clampedColumnInclusive(column + 1));
|
||||
}
|
||||
|
||||
// Returns the starting column of the glyph at the given column.
|
||||
// In other words, if you have 3 wide glyphs
|
||||
// AA BB CC
|
||||
// 01 23 45 <-- column
|
||||
// then `AdjustToGlyphStart(3)` returns 2.
|
||||
til::CoordType ROW::AdjustToGlyphStart(til::CoordType column) const noexcept
|
||||
{
|
||||
return _adjustBackward(_clampedColumn(column));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -719,11 +738,12 @@ try
|
||||
if (sourceColBeg < sourceColLimit)
|
||||
{
|
||||
charOffsets = source._charOffsets.subspan(sourceColBeg, static_cast<size_t>(sourceColLimit) - sourceColBeg + 1);
|
||||
const auto charsOffset = charOffsets.front() & CharOffsetsMask;
|
||||
const auto beg = size_t{ charOffsets.front() } & CharOffsetsMask;
|
||||
const auto end = size_t{ charOffsets.back() } & CharOffsetsMask;
|
||||
// We _are_ using span. But C++ decided that string_view and span aren't convertible.
|
||||
// _chars is a std::span for performance and because it refers to raw, shared memory.
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
chars = { source._chars.data() + charsOffset, source._chars.size() - charsOffset };
|
||||
chars = { source._chars.data() + beg, end - beg };
|
||||
}
|
||||
|
||||
WriteHelper h{ *this, state.columnBegin, state.columnLimit, chars };
|
||||
@@ -939,6 +959,16 @@ til::CoordType ROW::MeasureLeft() const noexcept
|
||||
|
||||
til::CoordType ROW::MeasureRight() const noexcept
|
||||
{
|
||||
if (_wrapForced)
|
||||
{
|
||||
auto width = _columnCount;
|
||||
if (_doubleBytePadded)
|
||||
{
|
||||
width--;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
|
||||
@@ -136,6 +136,7 @@ public:
|
||||
|
||||
til::CoordType NavigateToPrevious(til::CoordType column) const noexcept;
|
||||
til::CoordType NavigateToNext(til::CoordType column) const noexcept;
|
||||
til::CoordType AdjustToGlyphStart(til::CoordType column) const noexcept;
|
||||
|
||||
void ClearCell(til::CoordType column);
|
||||
OutputCellIterator WriteCells(OutputCellIterator it, til::CoordType columnBegin, std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
// Keeping TextColor compact helps us keeping TextAttribute compact,
|
||||
// which in turn ensures that our buffer memory usage is low.
|
||||
static_assert(sizeof(TextAttribute) == 12);
|
||||
static_assert(sizeof(TextAttribute) == 16);
|
||||
static_assert(alignof(TextAttribute) == 2);
|
||||
// Ensure that we can memcpy() and memmove() the struct for performance.
|
||||
static_assert(std::is_trivially_copyable_v<TextAttribute>);
|
||||
@@ -156,6 +156,25 @@ uint16_t TextAttribute::GetHyperlinkId() const noexcept
|
||||
return _hyperlinkId;
|
||||
}
|
||||
|
||||
TextColor TextAttribute::GetUnderlineColor() const noexcept
|
||||
{
|
||||
return _underlineColor;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Retrieves the underline style of the text.
|
||||
// - If the attribute is not the **current** attribute of the text buffer,
|
||||
// (eg. reading an attribute from another part of the text buffer, which
|
||||
// was modified using DECRARA), this might return an invalid style. In this
|
||||
// case, treat the style as singly underlined.
|
||||
// Return value:
|
||||
// - The underline style.
|
||||
UnderlineStyle TextAttribute::GetUnderlineStyle() const noexcept
|
||||
{
|
||||
const auto styleAttr = WI_EnumValue(_attrs & CharacterAttributes::UnderlineStyle);
|
||||
return static_cast<UnderlineStyle>(styleAttr >> UNDERLINE_STYLE_SHIFT);
|
||||
}
|
||||
|
||||
void TextAttribute::SetForeground(const TextColor foreground) noexcept
|
||||
{
|
||||
_foreground = foreground;
|
||||
@@ -166,6 +185,13 @@ void TextAttribute::SetBackground(const TextColor background) noexcept
|
||||
_background = background;
|
||||
}
|
||||
|
||||
void TextAttribute::SetUnderlineColor(const TextColor color) noexcept
|
||||
{
|
||||
// Index16 colors are not supported for underline colors.
|
||||
assert(!color.IsIndex16());
|
||||
_underlineColor = color;
|
||||
}
|
||||
|
||||
void TextAttribute::SetForeground(const COLORREF rgbForeground) noexcept
|
||||
{
|
||||
_foreground = TextColor(rgbForeground);
|
||||
@@ -277,14 +303,12 @@ bool TextAttribute::IsCrossedOut() const noexcept
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::CrossedOut);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Returns true if the text is underlined with any underline style.
|
||||
bool TextAttribute::IsUnderlined() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Underlined);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsDoublyUnderlined() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::DoublyUnderlined);
|
||||
const auto style = GetUnderlineStyle();
|
||||
return (style != UnderlineStyle::NoUnderline);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsOverlined() const noexcept
|
||||
@@ -332,14 +356,14 @@ void TextAttribute::SetCrossedOut(bool isCrossedOut) noexcept
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::CrossedOut, isCrossedOut);
|
||||
}
|
||||
|
||||
void TextAttribute::SetUnderlined(bool isUnderlined) noexcept
|
||||
// Method description:
|
||||
// - Sets underline style to singly, doubly, or one of the extended styles.
|
||||
// Arguments:
|
||||
// - style - underline style to set.
|
||||
void TextAttribute::SetUnderlineStyle(const UnderlineStyle style) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Underlined, isUnderlined);
|
||||
}
|
||||
|
||||
void TextAttribute::SetDoublyUnderlined(bool isDoublyUnderlined) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::DoublyUnderlined, isDoublyUnderlined);
|
||||
const auto shiftedStyle = WI_EnumValue(style) << UNDERLINE_STYLE_SHIFT;
|
||||
_attrs = (_attrs & ~CharacterAttributes::UnderlineStyle) | static_cast<CharacterAttributes>(shiftedStyle);
|
||||
}
|
||||
|
||||
void TextAttribute::SetOverlined(bool isOverlined) noexcept
|
||||
@@ -374,6 +398,11 @@ void TextAttribute::SetDefaultBackground() noexcept
|
||||
_background = TextColor();
|
||||
}
|
||||
|
||||
void TextAttribute::SetDefaultUnderlineColor() noexcept
|
||||
{
|
||||
_underlineColor = TextColor{};
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Resets only the rendition character attributes, which includes everything
|
||||
// except the Protected attribute.
|
||||
|
||||
@@ -27,6 +27,17 @@ Revision History:
|
||||
#include "WexTestClass.h"
|
||||
#endif
|
||||
|
||||
enum class UnderlineStyle
|
||||
{
|
||||
NoUnderline = 0U,
|
||||
SinglyUnderlined = 1U,
|
||||
DoublyUnderlined = 2U,
|
||||
CurlyUnderlined = 3U,
|
||||
DottedUnderlined = 4U,
|
||||
DashedUnderlined = 5U,
|
||||
Max = DashedUnderlined
|
||||
};
|
||||
|
||||
class TextAttribute final
|
||||
{
|
||||
public:
|
||||
@@ -34,7 +45,8 @@ public:
|
||||
_attrs{ CharacterAttributes::Normal },
|
||||
_foreground{},
|
||||
_background{},
|
||||
_hyperlinkId{ 0 }
|
||||
_hyperlinkId{ 0 },
|
||||
_underlineColor{}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,16 +54,28 @@ public:
|
||||
_attrs{ gsl::narrow_cast<WORD>(wLegacyAttr & USED_META_ATTRS) },
|
||||
_foreground{ gsl::at(s_legacyForegroundColorMap, wLegacyAttr & FG_ATTRS) },
|
||||
_background{ gsl::at(s_legacyBackgroundColorMap, (wLegacyAttr & BG_ATTRS) >> 4) },
|
||||
_hyperlinkId{ 0 }
|
||||
_hyperlinkId{ 0 },
|
||||
_underlineColor{}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TextAttribute(const COLORREF rgbForeground,
|
||||
const COLORREF rgbBackground) noexcept :
|
||||
const COLORREF rgbBackground,
|
||||
const COLORREF rgbUnderline = INVALID_COLOR) noexcept :
|
||||
_attrs{ CharacterAttributes::Normal },
|
||||
_foreground{ rgbForeground },
|
||||
_background{ rgbBackground },
|
||||
_hyperlinkId{ 0 }
|
||||
_hyperlinkId{ 0 },
|
||||
_underlineColor{ rgbUnderline }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TextAttribute(const CharacterAttributes attrs, const TextColor foreground, const TextColor background, const uint16_t hyperlinkId, const TextColor underlineColor) noexcept :
|
||||
_attrs{ attrs },
|
||||
_foreground{ foreground },
|
||||
_background{ background },
|
||||
_hyperlinkId{ hyperlinkId },
|
||||
_underlineColor{ underlineColor }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -87,7 +111,6 @@ public:
|
||||
bool IsInvisible() const noexcept;
|
||||
bool IsCrossedOut() const noexcept;
|
||||
bool IsUnderlined() const noexcept;
|
||||
bool IsDoublyUnderlined() const noexcept;
|
||||
bool IsOverlined() const noexcept;
|
||||
bool IsReverseVideo() const noexcept;
|
||||
bool IsProtected() const noexcept;
|
||||
@@ -98,8 +121,7 @@ public:
|
||||
void SetBlinking(bool isBlinking) noexcept;
|
||||
void SetInvisible(bool isInvisible) noexcept;
|
||||
void SetCrossedOut(bool isCrossedOut) noexcept;
|
||||
void SetUnderlined(bool isUnderlined) noexcept;
|
||||
void SetDoublyUnderlined(bool isDoublyUnderlined) noexcept;
|
||||
void SetUnderlineStyle(const UnderlineStyle underlineStyle) noexcept;
|
||||
void SetOverlined(bool isOverlined) noexcept;
|
||||
void SetReverseVideo(bool isReversed) noexcept;
|
||||
void SetProtected(bool isProtected) noexcept;
|
||||
@@ -118,8 +140,11 @@ public:
|
||||
TextColor GetForeground() const noexcept;
|
||||
TextColor GetBackground() const noexcept;
|
||||
uint16_t GetHyperlinkId() const noexcept;
|
||||
TextColor GetUnderlineColor() const noexcept;
|
||||
UnderlineStyle GetUnderlineStyle() const noexcept;
|
||||
void SetForeground(const TextColor foreground) noexcept;
|
||||
void SetBackground(const TextColor background) noexcept;
|
||||
void SetUnderlineColor(const TextColor color) noexcept;
|
||||
void SetForeground(const COLORREF rgbForeground) noexcept;
|
||||
void SetBackground(const COLORREF rgbBackground) noexcept;
|
||||
void SetIndexedForeground(const BYTE fgIndex) noexcept;
|
||||
@@ -131,6 +156,7 @@ public:
|
||||
|
||||
void SetDefaultForeground() noexcept;
|
||||
void SetDefaultBackground() noexcept;
|
||||
void SetDefaultUnderlineColor() noexcept;
|
||||
void SetDefaultRenditionAttributes() noexcept;
|
||||
|
||||
bool BackgroundIsDefault() const noexcept;
|
||||
@@ -147,8 +173,8 @@ public:
|
||||
// global ^ local == false: the foreground attribute is the visible foreground, so we care about the backgrounds being identical
|
||||
const auto checkForeground = (inverted != IsReverseVideo());
|
||||
return !IsAnyGridLineEnabled() && // grid lines have a visual representation
|
||||
// crossed out, doubly and singly underlined have a visual representation
|
||||
WI_AreAllFlagsClear(_attrs, CharacterAttributes::CrossedOut | CharacterAttributes::DoublyUnderlined | CharacterAttributes::Underlined) &&
|
||||
// styled underline and crossed out have a visual representation
|
||||
!IsUnderlined() && WI_IsFlagClear(_attrs, CharacterAttributes::CrossedOut) &&
|
||||
// hyperlinks have a visual representation
|
||||
!IsHyperlink() &&
|
||||
// all other attributes do not have a visual representation
|
||||
@@ -175,6 +201,7 @@ private:
|
||||
uint16_t _hyperlinkId; // sizeof: 2, alignof: 2
|
||||
TextColor _foreground; // sizeof: 4, alignof: 1
|
||||
TextColor _background; // sizeof: 4, alignof: 1
|
||||
TextColor _underlineColor; // sizeof: 4, alignof: 1
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
|
||||
@@ -14,16 +14,15 @@ bool Search::ResetIfStale(Microsoft::Console::Render::IRenderData& renderData, c
|
||||
const auto lastMutationId = textBuffer.GetLastMutationId();
|
||||
|
||||
if (_needle == needle &&
|
||||
_reverse == reverse &&
|
||||
_caseInsensitive == caseInsensitive &&
|
||||
_lastMutationId == lastMutationId)
|
||||
{
|
||||
_step = reverse ? -1 : 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
_renderData = &renderData;
|
||||
_needle = needle;
|
||||
_reverse = reverse;
|
||||
_caseInsensitive = caseInsensitive;
|
||||
_lastMutationId = lastMutationId;
|
||||
|
||||
@@ -34,14 +33,40 @@ bool Search::ResetIfStale(Microsoft::Console::Render::IRenderData& renderData, c
|
||||
return true;
|
||||
}
|
||||
|
||||
void Search::MovePastCurrentSelection()
|
||||
void Search::MoveToCurrentSelection()
|
||||
{
|
||||
if (_renderData->IsSelectionActive())
|
||||
{
|
||||
MovePastPoint(_renderData->GetTextBuffer().ScreenToBufferPosition(_renderData->GetSelectionAnchor()));
|
||||
MoveToPoint(_renderData->GetTextBuffer().ScreenToBufferPosition(_renderData->GetSelectionAnchor()));
|
||||
}
|
||||
}
|
||||
|
||||
void Search::MoveToPoint(const til::point anchor) noexcept
|
||||
{
|
||||
if (_results.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto count = gsl::narrow_cast<ptrdiff_t>(_results.size());
|
||||
ptrdiff_t index = 0;
|
||||
|
||||
if (_step < 0)
|
||||
{
|
||||
for (index = count - 1; index >= 0 && til::at(_results, index).start > anchor; --index)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (index = 0; index < count && til::at(_results, index).start < anchor; ++index)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
_index = (index + count) % count;
|
||||
}
|
||||
|
||||
void Search::MovePastPoint(const til::point anchor) noexcept
|
||||
{
|
||||
if (_results.empty())
|
||||
@@ -50,18 +75,17 @@ void Search::MovePastPoint(const til::point anchor) noexcept
|
||||
}
|
||||
|
||||
const auto count = gsl::narrow_cast<ptrdiff_t>(_results.size());
|
||||
const auto highestIndex = count - 1;
|
||||
auto index = _reverse ? highestIndex : 0;
|
||||
ptrdiff_t index = 0;
|
||||
|
||||
if (_reverse)
|
||||
if (_step < 0)
|
||||
{
|
||||
for (; index >= 0 && til::at(_results, index).start >= anchor; --index)
|
||||
for (index = count - 1; index >= 0 && til::at(_results, index).start >= anchor; --index)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; index <= highestIndex && til::at(_results, index).start <= anchor; ++index)
|
||||
for (index = 0; index < count && til::at(_results, index).start <= anchor; ++index)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -71,8 +95,10 @@ void Search::MovePastPoint(const til::point anchor) noexcept
|
||||
|
||||
void Search::FindNext() noexcept
|
||||
{
|
||||
const auto count = gsl::narrow_cast<ptrdiff_t>(_results.size());
|
||||
_index = (_index + _step + count) % count;
|
||||
if (const auto count{ gsl::narrow_cast<ptrdiff_t>(_results.size()) })
|
||||
{
|
||||
_index = (_index + _step + count) % count;
|
||||
}
|
||||
}
|
||||
|
||||
const til::point_span* Search::GetCurrent() const noexcept
|
||||
@@ -85,8 +111,31 @@ const til::point_span* Search::GetCurrent() const noexcept
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Search::HighlightResults() const
|
||||
{
|
||||
std::vector<til::inclusive_rect> toSelect;
|
||||
const auto& textBuffer = _renderData->GetTextBuffer();
|
||||
|
||||
for (const auto& r : _results)
|
||||
{
|
||||
const auto rbStart = textBuffer.BufferToScreenPosition(r.start);
|
||||
const auto rbEnd = textBuffer.BufferToScreenPosition(r.end);
|
||||
|
||||
til::inclusive_rect re;
|
||||
re.top = rbStart.y;
|
||||
re.bottom = rbEnd.y;
|
||||
re.left = rbStart.x;
|
||||
re.right = rbEnd.x;
|
||||
|
||||
toSelect.emplace_back(re);
|
||||
}
|
||||
|
||||
_renderData->SelectSearchRegions(std::move(toSelect));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Takes the found word and selects it in the screen buffer
|
||||
|
||||
bool Search::SelectCurrent() const
|
||||
{
|
||||
if (const auto s = GetCurrent())
|
||||
@@ -100,5 +149,16 @@ bool Search::SelectCurrent() const
|
||||
return true;
|
||||
}
|
||||
|
||||
_renderData->ClearSelection();
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<til::point_span>& Search::Results() const noexcept
|
||||
{
|
||||
return _results;
|
||||
}
|
||||
|
||||
ptrdiff_t Search::CurrentMatch() const noexcept
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
|
||||
@@ -27,18 +27,22 @@ public:
|
||||
|
||||
bool ResetIfStale(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool reverse, bool caseInsensitive);
|
||||
|
||||
void MovePastCurrentSelection();
|
||||
void MoveToCurrentSelection();
|
||||
void MoveToPoint(til::point anchor) noexcept;
|
||||
void MovePastPoint(til::point anchor) noexcept;
|
||||
void FindNext() noexcept;
|
||||
|
||||
const til::point_span* GetCurrent() const noexcept;
|
||||
void HighlightResults() const;
|
||||
bool SelectCurrent() const;
|
||||
|
||||
const std::vector<til::point_span>& Results() const noexcept;
|
||||
ptrdiff_t CurrentMatch() const noexcept;
|
||||
|
||||
private:
|
||||
// _renderData is a pointer so that Search() is constexpr default constructable.
|
||||
Microsoft::Console::Render::IRenderData* _renderData = nullptr;
|
||||
std::wstring_view _needle;
|
||||
bool _reverse = false;
|
||||
std::wstring _needle;
|
||||
bool _caseInsensitive = false;
|
||||
uint64_t _lastMutationId = 0;
|
||||
|
||||
|
||||
@@ -416,6 +416,88 @@ size_t TextBuffer::GraphemePrev(const std::wstring_view& chars, size_t position)
|
||||
return til::utf16_iterate_prev(chars, position);
|
||||
}
|
||||
|
||||
// Ever wondered how much space a piece of text needs before inserting it? This function will tell you!
|
||||
// It fundamentally behaves identical to the various ROW functions around `RowWriteState`.
|
||||
//
|
||||
// Set `columnLimit` to the amount of space that's available (e.g. `buffer_width - cursor_position.x`)
|
||||
// and it'll return the amount of characters that fit into this space. The out parameter `columns`
|
||||
// will contain the amount of columns this piece of text has actually used.
|
||||
//
|
||||
// Just like with `RowWriteState` one special case is when not all text fits into the given space:
|
||||
// In that case, this function always returns exactly `columnLimit`. This distinction is important when "inserting"
|
||||
// a wide glyph but there's only 1 column left. That 1 remaining column is supposed to be padded with whitespace.
|
||||
size_t TextBuffer::FitTextIntoColumns(const std::wstring_view& chars, til::CoordType columnLimit, til::CoordType& columns) noexcept
|
||||
{
|
||||
columnLimit = std::max(0, columnLimit);
|
||||
|
||||
const auto beg = chars.begin();
|
||||
const auto end = chars.end();
|
||||
auto it = beg;
|
||||
const auto asciiEnd = beg + std::min(chars.size(), gsl::narrow_cast<size_t>(columnLimit));
|
||||
|
||||
// ASCII fast-path: 1 char always corresponds to 1 column.
|
||||
for (; it != asciiEnd && *it < 0x80; ++it)
|
||||
{
|
||||
}
|
||||
|
||||
const auto dist = gsl::narrow_cast<size_t>(it - beg);
|
||||
auto col = gsl::narrow_cast<til::CoordType>(dist);
|
||||
|
||||
if (it == asciiEnd) [[likely]]
|
||||
{
|
||||
columns = col;
|
||||
return dist;
|
||||
}
|
||||
|
||||
// Unicode slow-path where we need to count text and columns separately.
|
||||
for (;;)
|
||||
{
|
||||
auto ptr = &*it;
|
||||
const auto wch = *ptr;
|
||||
size_t len = 1;
|
||||
|
||||
col++;
|
||||
|
||||
// Even in our slow-path we can avoid calling IsGlyphFullWidth if the current character is ASCII.
|
||||
// It also allows us to skip the surrogate pair decoding at the same time.
|
||||
if (wch >= 0x80)
|
||||
{
|
||||
if (til::is_surrogate(wch))
|
||||
{
|
||||
const auto it2 = it + 1;
|
||||
if (til::is_leading_surrogate(wch) && it2 != end && til::is_trailing_surrogate(*it2))
|
||||
{
|
||||
len = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = &UNICODE_REPLACEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
col += IsGlyphFullWidth({ ptr, len });
|
||||
}
|
||||
|
||||
// If we ran out of columns, we need to always return `columnLimit` and not `cols`,
|
||||
// because if we tried inserting a wide glyph into just 1 remaining column it will
|
||||
// fail to fit, but that remaining column still has been used up. When the caller sees
|
||||
// `columns == columnLimit` they will line-wrap and continue inserting into the next row.
|
||||
if (col > columnLimit)
|
||||
{
|
||||
columns = columnLimit;
|
||||
return gsl::narrow_cast<size_t>(it - beg);
|
||||
}
|
||||
|
||||
// But if we simply ran out of text we just need to return the actual number of columns.
|
||||
it += len;
|
||||
if (it == end)
|
||||
{
|
||||
columns = col;
|
||||
return chars.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pretend as if `position` is a regular cursor in the TextBuffer.
|
||||
// This function will then pretend as if you pressed the left/right arrow
|
||||
// keys `distance` amount of times (negative = left, positive = right).
|
||||
@@ -806,9 +888,9 @@ void TextBuffer::IncrementCircularBuffer(const TextAttribute& fillAttributes)
|
||||
// - The viewport
|
||||
//Return value:
|
||||
// - Coordinate position (relative to the text buffer)
|
||||
til::point TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional) const
|
||||
til::point TextBuffer::GetLastNonSpaceCharacter(const Viewport* viewOptional) const
|
||||
{
|
||||
const auto viewport = viewOptional.has_value() ? viewOptional.value() : GetSize();
|
||||
const auto viewport = viewOptional ? *viewOptional : GetSize();
|
||||
|
||||
til::point coordEndOfText;
|
||||
// Search the given viewport by starting at the bottom.
|
||||
@@ -1070,46 +1152,40 @@ void TextBuffer::Reset() noexcept
|
||||
// - newSize - new size of screen.
|
||||
// Return Value:
|
||||
// - Success if successful. Invalid parameter if screen buffer size is unexpected. No memory if allocation failed.
|
||||
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(til::size newSize) noexcept
|
||||
void TextBuffer::ResizeTraditional(til::size newSize)
|
||||
{
|
||||
// Guard against resizing the text buffer to 0 columns/rows, which would break being able to insert text.
|
||||
newSize.width = std::max(newSize.width, 1);
|
||||
newSize.height = std::max(newSize.height, 1);
|
||||
|
||||
try
|
||||
TextBuffer newBuffer{ newSize, _currentAttributes, 0, false, _renderer };
|
||||
const auto cursorRow = GetCursor().GetPosition().y;
|
||||
const auto copyableRows = std::min<til::CoordType>(_height, newSize.height);
|
||||
til::CoordType srcRow = 0;
|
||||
til::CoordType dstRow = 0;
|
||||
|
||||
if (cursorRow >= newSize.height)
|
||||
{
|
||||
TextBuffer newBuffer{ newSize, _currentAttributes, 0, false, _renderer };
|
||||
const auto cursorRow = GetCursor().GetPosition().y;
|
||||
const auto copyableRows = std::min<til::CoordType>(_height, newSize.height);
|
||||
til::CoordType srcRow = 0;
|
||||
til::CoordType dstRow = 0;
|
||||
|
||||
if (cursorRow >= newSize.height)
|
||||
{
|
||||
srcRow = cursorRow - newSize.height + 1;
|
||||
}
|
||||
|
||||
for (; dstRow < copyableRows; ++dstRow, ++srcRow)
|
||||
{
|
||||
newBuffer.GetMutableRowByOffset(dstRow).CopyFrom(GetRowByOffset(srcRow));
|
||||
}
|
||||
|
||||
// NOTE: Keep this in sync with _reserve().
|
||||
_buffer = std::move(newBuffer._buffer);
|
||||
_bufferEnd = newBuffer._bufferEnd;
|
||||
_commitWatermark = newBuffer._commitWatermark;
|
||||
_initialAttributes = newBuffer._initialAttributes;
|
||||
_bufferRowStride = newBuffer._bufferRowStride;
|
||||
_bufferOffsetChars = newBuffer._bufferOffsetChars;
|
||||
_bufferOffsetCharOffsets = newBuffer._bufferOffsetCharOffsets;
|
||||
_width = newBuffer._width;
|
||||
_height = newBuffer._height;
|
||||
|
||||
_SetFirstRowIndex(0);
|
||||
srcRow = cursorRow - newSize.height + 1;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
for (; dstRow < copyableRows; ++dstRow, ++srcRow)
|
||||
{
|
||||
newBuffer.GetMutableRowByOffset(dstRow).CopyFrom(GetRowByOffset(srcRow));
|
||||
}
|
||||
|
||||
// NOTE: Keep this in sync with _reserve().
|
||||
_buffer = std::move(newBuffer._buffer);
|
||||
_bufferEnd = newBuffer._bufferEnd;
|
||||
_commitWatermark = newBuffer._commitWatermark;
|
||||
_initialAttributes = newBuffer._initialAttributes;
|
||||
_bufferRowStride = newBuffer._bufferRowStride;
|
||||
_bufferOffsetChars = newBuffer._bufferOffsetChars;
|
||||
_bufferOffsetCharOffsets = newBuffer._bufferOffsetCharOffsets;
|
||||
_width = newBuffer._width;
|
||||
_height = newBuffer._height;
|
||||
|
||||
_SetFirstRowIndex(0);
|
||||
}
|
||||
|
||||
void TextBuffer::SetAsActiveBuffer(const bool isActiveBuffer) noexcept
|
||||
@@ -1253,36 +1329,32 @@ til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, co
|
||||
{
|
||||
auto result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
auto stayAtOrigin = false;
|
||||
|
||||
// ignore left boundary. Continue until readable text found
|
||||
while (_GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
|
||||
{
|
||||
if (!bufferSize.DecrementInBounds(result))
|
||||
if (result == bufferSize.Origin())
|
||||
{
|
||||
// first char in buffer is a DelimiterChar or ControlChar
|
||||
// we can't move any further back
|
||||
stayAtOrigin = true;
|
||||
break;
|
||||
//looped around and hit origin (no word between origin and target)
|
||||
return result;
|
||||
}
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
// make sure we expand to the left boundary or the beginning of the word
|
||||
while (_GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
|
||||
{
|
||||
if (!bufferSize.DecrementInBounds(result))
|
||||
if (result == bufferSize.Origin())
|
||||
{
|
||||
// first char in buffer is a RegularChar
|
||||
// we can't move any further back
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
// move off of delimiter and onto word start
|
||||
if (!stayAtOrigin && _GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
|
||||
{
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
// move off of delimiter
|
||||
bufferSize.IncrementInBounds(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1300,10 +1372,16 @@ til::point TextBuffer::_GetWordStartForSelection(const til::point target, const
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
|
||||
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
|
||||
|
||||
// expand left until we hit the left boundary or a different delimiter class
|
||||
while (result.x > bufferSize.Left() && (_GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter))
|
||||
while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
|
||||
{
|
||||
//prevent selection wrapping on whitespace selection
|
||||
if (isControlChar && result.x == bufferSize.Left())
|
||||
{
|
||||
break;
|
||||
}
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
@@ -1381,25 +1459,21 @@ til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, cons
|
||||
}
|
||||
else
|
||||
{
|
||||
auto iter{ GetCellDataAt(result, bufferSize) };
|
||||
while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) == DelimiterClass::RegularChar)
|
||||
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
|
||||
{
|
||||
// Iterate through readable text
|
||||
++iter;
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
|
||||
while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) != DelimiterClass::RegularChar)
|
||||
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
|
||||
{
|
||||
// expand to the beginning of the NEXT word
|
||||
++iter;
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
|
||||
result = iter.Pos();
|
||||
|
||||
// Special case: we tried to move one past the end of the buffer,
|
||||
// but iter prevented that (because that pos doesn't exist).
|
||||
// Special case: we tried to move one past the end of the buffer
|
||||
// Manually increment onto the EndExclusive point.
|
||||
if (!iter)
|
||||
if (result == bufferSize.BottomRightInclusive())
|
||||
{
|
||||
bufferSize.IncrementInBounds(result, true);
|
||||
}
|
||||
@@ -1419,19 +1493,18 @@ til::point TextBuffer::_GetWordEndForSelection(const til::point target, const st
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
// can't expand right
|
||||
if (target.x == bufferSize.RightInclusive())
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
auto result = target;
|
||||
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
|
||||
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
|
||||
|
||||
// expand right until we hit the right boundary or a different delimiter class
|
||||
while (result.x < bufferSize.RightInclusive() && (_GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter))
|
||||
// expand right until we hit the right boundary as a ControlChar or a different delimiter class
|
||||
while (result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
|
||||
{
|
||||
bufferSize.IncrementInBounds(result);
|
||||
if (isControlChar && result.x == bufferSize.RightInclusive())
|
||||
{
|
||||
break;
|
||||
}
|
||||
bufferSize.IncrementInBoundsCircular(result);
|
||||
}
|
||||
|
||||
if (_GetDelimiterClassAt(result, wordDelimiters) != initialDelimiter)
|
||||
@@ -2201,6 +2274,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
||||
// Routine Description:
|
||||
// - Generates an RTF document based on the passed in text and color data
|
||||
// RTF 1.5 Spec: https://www.biblioscape.com/rtf15_spec.htm
|
||||
// RTF 1.9.1 Spec: https://msopenspecs.azureedge.net/files/Archive_References/[MSFT-RTF].pdf
|
||||
// Arguments:
|
||||
// - rows - the text and color data we will format & encapsulate
|
||||
// - backgroundColor - default background color for characters, also used in padding
|
||||
@@ -2220,10 +2294,18 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
|
||||
|
||||
// Standard RTF header.
|
||||
// This is similar to the header generated by WordPad.
|
||||
// \ansi - specifies that the ANSI char set is used in the current doc
|
||||
// \ansicpg1252 - represents the ANSI code page which is used to perform the Unicode to ANSI conversion when writing RTF text
|
||||
// \deff0 - specifies that the default font for the document is the one at index 0 in the font table
|
||||
// \nouicompat - ?
|
||||
// \ansi:
|
||||
// Specifies that the ANSI char set is used in the current doc.
|
||||
// \ansicpg1252:
|
||||
// Represents the ANSI code page which is used to perform
|
||||
// the Unicode to ANSI conversion when writing RTF text.
|
||||
// \deff0:
|
||||
// Specifies that the default font for the document is the one
|
||||
// at index 0 in the font table.
|
||||
// \nouicompat:
|
||||
// Some features are blocked by default to maintain compatibility
|
||||
// with older programs (Eg. Word 97-2003). `nouicompat` disables this
|
||||
// behavior, and unblocks these features. See: Spec 1.9.1, Pg. 51.
|
||||
rtfBuilder << "\\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat";
|
||||
|
||||
// font table
|
||||
@@ -2232,17 +2314,25 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
|
||||
// map to keep track of colors:
|
||||
// keys are colors represented by COLORREF
|
||||
// values are indices of the corresponding colors in the color table
|
||||
std::unordered_map<COLORREF, int> colorMap;
|
||||
auto nextColorIndex = 1; // leave 0 for the default color and start from 1.
|
||||
std::unordered_map<COLORREF, size_t> colorMap;
|
||||
|
||||
// RTF color table
|
||||
std::ostringstream colorTableBuilder;
|
||||
colorTableBuilder << "{\\colortbl ;";
|
||||
colorTableBuilder << "\\red" << static_cast<int>(GetRValue(backgroundColor))
|
||||
<< "\\green" << static_cast<int>(GetGValue(backgroundColor))
|
||||
<< "\\blue" << static_cast<int>(GetBValue(backgroundColor))
|
||||
<< ";";
|
||||
colorMap[backgroundColor] = nextColorIndex++;
|
||||
|
||||
const auto getColorTableIndex = [&](const COLORREF color) -> size_t {
|
||||
// Exclude the 0 index for the default color, and start with 1.
|
||||
|
||||
const auto [it, inserted] = colorMap.emplace(color, colorMap.size() + 1);
|
||||
if (inserted)
|
||||
{
|
||||
colorTableBuilder << "\\red" << static_cast<int>(GetRValue(color))
|
||||
<< "\\green" << static_cast<int>(GetGValue(color))
|
||||
<< "\\blue" << static_cast<int>(GetBValue(color))
|
||||
<< ";";
|
||||
}
|
||||
return it->second;
|
||||
};
|
||||
|
||||
// content
|
||||
std::ostringstream contentBuilder;
|
||||
@@ -2252,7 +2342,12 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
|
||||
// \fs specifies font size in half-points i.e. \fs20 results in a font size
|
||||
// of 10 pts. That's why, font size is multiplied by 2 here.
|
||||
contentBuilder << "\\pard\\slmult1\\f0\\fs" << std::to_string(2 * fontHeightPoints)
|
||||
<< "\\highlight1"
|
||||
// Set the background color for the page. But, the
|
||||
// standard way (\cbN) to do this isn't supported in Word.
|
||||
// However, the following control words sequence works
|
||||
// in Word (and other RTF editors also) for applying the
|
||||
// text background color. See: Spec 1.9.1, Pg. 23.
|
||||
<< "\\chshdng0\\chcbpat" << getColorTableIndex(backgroundColor)
|
||||
<< " ";
|
||||
|
||||
std::optional<COLORREF> fgColor = std::nullopt;
|
||||
@@ -2302,43 +2397,8 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
|
||||
if (colorChanged)
|
||||
{
|
||||
writeAccumulatedChars(false);
|
||||
|
||||
auto bkColorIndex = 0;
|
||||
if (colorMap.find(bkColor.value()) != colorMap.end())
|
||||
{
|
||||
// color already exists in the map, just retrieve the index
|
||||
bkColorIndex = colorMap[bkColor.value()];
|
||||
}
|
||||
else
|
||||
{
|
||||
// color not present in the map, so add it
|
||||
colorTableBuilder << "\\red" << static_cast<int>(GetRValue(bkColor.value()))
|
||||
<< "\\green" << static_cast<int>(GetGValue(bkColor.value()))
|
||||
<< "\\blue" << static_cast<int>(GetBValue(bkColor.value()))
|
||||
<< ";";
|
||||
colorMap[bkColor.value()] = nextColorIndex;
|
||||
bkColorIndex = nextColorIndex++;
|
||||
}
|
||||
|
||||
auto fgColorIndex = 0;
|
||||
if (colorMap.find(fgColor.value()) != colorMap.end())
|
||||
{
|
||||
// color already exists in the map, just retrieve the index
|
||||
fgColorIndex = colorMap[fgColor.value()];
|
||||
}
|
||||
else
|
||||
{
|
||||
// color not present in the map, so add it
|
||||
colorTableBuilder << "\\red" << static_cast<int>(GetRValue(fgColor.value()))
|
||||
<< "\\green" << static_cast<int>(GetGValue(fgColor.value()))
|
||||
<< "\\blue" << static_cast<int>(GetBValue(fgColor.value()))
|
||||
<< ";";
|
||||
colorMap[fgColor.value()] = nextColorIndex;
|
||||
fgColorIndex = nextColorIndex++;
|
||||
}
|
||||
|
||||
contentBuilder << "\\highlight" << bkColorIndex
|
||||
<< "\\cf" << fgColorIndex
|
||||
contentBuilder << "\\chshdng0\\chcbpat" << getColorTableIndex(bkColor.value())
|
||||
<< "\\cf" << getColorTableIndex(fgColor.value())
|
||||
<< " ";
|
||||
}
|
||||
|
||||
@@ -2412,204 +2472,181 @@ void TextBuffer::_AppendRTFText(std::ostringstream& contentBuilder, const std::w
|
||||
// the new buffer. The rows's new value is placed back into this parameter.
|
||||
// Return Value:
|
||||
// - S_OK if we successfully copied the contents to the new buffer, otherwise an appropriate HRESULT.
|
||||
HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
||||
TextBuffer& newBuffer,
|
||||
const std::optional<Viewport> lastCharacterViewport,
|
||||
std::optional<std::reference_wrapper<PositionInformation>> positionInfo)
|
||||
try
|
||||
void TextBuffer::Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const Viewport* lastCharacterViewport, PositionInformation* positionInfo)
|
||||
{
|
||||
const auto& oldCursor = oldBuffer.GetCursor();
|
||||
auto& newCursor = newBuffer.GetCursor();
|
||||
|
||||
// We need to save the old cursor position so that we can
|
||||
// place the new cursor back on the equivalent character in
|
||||
// the new buffer.
|
||||
const auto cOldCursorPos = oldCursor.GetPosition();
|
||||
const auto cOldLastChar = oldBuffer.GetLastNonSpaceCharacter(lastCharacterViewport);
|
||||
til::point oldCursorPos = oldCursor.GetPosition();
|
||||
til::point newCursorPos;
|
||||
|
||||
const auto cOldRowsTotal = cOldLastChar.y + 1;
|
||||
// BODGY: We use oldCursorPos in two critical places below:
|
||||
// * To compute an oldHeight that includes at a minimum the cursor row
|
||||
// * For REFLOW_JANK_CURSOR_WRAP (see comment below)
|
||||
// Both of these would break the reflow algorithm, but the latter of the two in particular
|
||||
// would cause the main copy loop below to deadlock. In other words, these two lines
|
||||
// protect this function against yet-unknown bugs in other parts of the code base.
|
||||
oldCursorPos.x = std::clamp(oldCursorPos.x, 0, oldBuffer._width - 1);
|
||||
oldCursorPos.y = std::clamp(oldCursorPos.y, 0, oldBuffer._height - 1);
|
||||
|
||||
til::point cNewCursorPos;
|
||||
auto fFoundCursorPos = false;
|
||||
auto foundOldMutable = false;
|
||||
auto foundOldVisible = false;
|
||||
// Loop through all the rows of the old buffer and reprint them into the new buffer
|
||||
til::CoordType iOldRow = 0;
|
||||
for (; iOldRow < cOldRowsTotal; iOldRow++)
|
||||
const auto lastRowWithText = oldBuffer.GetLastNonSpaceCharacter(lastCharacterViewport).y;
|
||||
|
||||
auto mutableViewportTop = positionInfo ? positionInfo->mutableViewportTop : til::CoordTypeMax;
|
||||
auto visibleViewportTop = positionInfo ? positionInfo->visibleViewportTop : til::CoordTypeMax;
|
||||
|
||||
til::CoordType oldY = 0;
|
||||
til::CoordType newY = 0;
|
||||
til::CoordType newX = 0;
|
||||
til::CoordType newWidth = newBuffer.GetSize().Width();
|
||||
til::CoordType newYLimit = til::CoordTypeMax;
|
||||
|
||||
const auto oldHeight = std::max(lastRowWithText, oldCursorPos.y) + 1;
|
||||
const auto newHeight = newBuffer.GetSize().Height();
|
||||
const auto newWidthU16 = gsl::narrow_cast<uint16_t>(newWidth);
|
||||
|
||||
// Copy oldBuffer into newBuffer until oldBuffer has been fully consumed.
|
||||
for (; oldY < oldHeight && newY < newYLimit; ++oldY)
|
||||
{
|
||||
// Fetch the row and its "right" which is the last printable character.
|
||||
const auto& row = oldBuffer.GetRowByOffset(iOldRow);
|
||||
const auto cOldColsTotal = oldBuffer.GetLineWidth(iOldRow);
|
||||
auto iRight = row.MeasureRight();
|
||||
const auto& oldRow = oldBuffer.GetRowByOffset(oldY);
|
||||
|
||||
// If we're starting a new row, try and preserve the line rendition
|
||||
// from the row in the original buffer.
|
||||
const auto newBufferPos = newCursor.GetPosition();
|
||||
if (newBufferPos.x == 0)
|
||||
// A pair of double height rows should optimally wrap as a union (i.e. after wrapping there should be 4 lines).
|
||||
// But for this initial implementation I chose the alternative approach: Just truncate them.
|
||||
if (oldRow.GetLineRendition() != LineRendition::SingleWidth)
|
||||
{
|
||||
auto& newRow = newBuffer.GetMutableRowByOffset(newBufferPos.y);
|
||||
newRow.SetLineRendition(row.GetLineRendition());
|
||||
}
|
||||
|
||||
// There is a special case here. If the row has a "wrap"
|
||||
// flag on it, but the right isn't equal to the width (one
|
||||
// index past the final valid index in the row) then there
|
||||
// were a bunch trailing of spaces in the row.
|
||||
// (But the measuring functions for each row Left/Right do
|
||||
// not count spaces as "displayable" so they're not
|
||||
// included.)
|
||||
// As such, adjust the "right" to be the width of the row
|
||||
// to capture all these spaces
|
||||
if (row.WasWrapForced())
|
||||
{
|
||||
iRight = cOldColsTotal;
|
||||
|
||||
// And a combined special case.
|
||||
// If we wrapped off the end of the row by adding a
|
||||
// piece of padding because of a double byte LEADING
|
||||
// character, then remove one from the "right" to
|
||||
// leave this padding out of the copy process.
|
||||
if (row.WasDoubleBytePadded())
|
||||
// Since rows with a non-standard line rendition should be truncated it's important
|
||||
// that we pretend as if the previous row ended in a newline, even if it didn't.
|
||||
// This is what this if does: It newlines.
|
||||
if (newX)
|
||||
{
|
||||
iRight--;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through every character in the current row (up to
|
||||
// the "right" boundary, which is one past the final valid
|
||||
// character)
|
||||
til::CoordType iOldCol = 0;
|
||||
const auto copyRight = iRight;
|
||||
for (; iOldCol < copyRight; iOldCol++)
|
||||
{
|
||||
if (iOldCol == cOldCursorPos.x && iOldRow == cOldCursorPos.y)
|
||||
{
|
||||
cNewCursorPos = newCursor.GetPosition();
|
||||
fFoundCursorPos = true;
|
||||
newX = 0;
|
||||
newY++;
|
||||
}
|
||||
|
||||
// TODO: MSFT: 19446208 - this should just use an iterator and the inserter...
|
||||
const auto glyph = row.GlyphAt(iOldCol);
|
||||
const auto dbcsAttr = row.DbcsAttrAt(iOldCol);
|
||||
const auto textAttr = row.GetAttrByColumn(iOldCol);
|
||||
auto& newRow = newBuffer.GetMutableRowByOffset(newY);
|
||||
|
||||
newBuffer.InsertCharacter(glyph, dbcsAttr, textAttr);
|
||||
}
|
||||
|
||||
// GH#32: Copy the attributes from the rest of the row into this new buffer.
|
||||
// From where we are in the old buffer, to the end of the row, copy the
|
||||
// remaining attributes.
|
||||
// - if the old buffer is smaller than the new buffer, then just copy
|
||||
// what we have, as it was. We already copied all _text_ with colors,
|
||||
// but it's possible for someone to just put some color into the
|
||||
// buffer to the right of that without any text (as just spaces). The
|
||||
// buffer looks weird to the user when we resize and it starts losing
|
||||
// those colors, so we need to copy them over too... as long as there
|
||||
// is space. The last attr in the row will be extended to the end of
|
||||
// the row in the new buffer.
|
||||
// - if the old buffer is WIDER, than we might have wrapped onto a new
|
||||
// line. Use the cursor's position's Y so that we know where the new
|
||||
// row is, and start writing at the cursor position. Again, the attr
|
||||
// in the last column of the old row will be extended to the end of the
|
||||
// row that the text was flowed onto.
|
||||
// - if the text in the old buffer didn't actually fill the whole
|
||||
// line in the new buffer, then we didn't wrap. That's fine. just
|
||||
// copy attributes from the old row till the end of the new row, and
|
||||
// move on.
|
||||
const auto newRowY = newCursor.GetPosition().y;
|
||||
auto& newRow = newBuffer.GetMutableRowByOffset(newRowY);
|
||||
auto newAttrColumn = newCursor.GetPosition().x;
|
||||
const auto newWidth = newBuffer.GetLineWidth(newRowY);
|
||||
// Stop when we get to the end of the buffer width, or the new position
|
||||
// for inserting an attr would be past the right of the new buffer.
|
||||
for (auto copyAttrCol = iOldCol;
|
||||
copyAttrCol < cOldColsTotal && newAttrColumn < newWidth;
|
||||
copyAttrCol++, newAttrColumn++)
|
||||
{
|
||||
// TODO: MSFT: 19446208 - this should just use an iterator and the inserter...
|
||||
const auto textAttr = row.GetAttrByColumn(copyAttrCol);
|
||||
newRow.SetAttrToEnd(newAttrColumn, textAttr);
|
||||
}
|
||||
|
||||
// If we found the old row that the caller was interested in, set the
|
||||
// out value of that parameter to the cursor's current Y position (the
|
||||
// new location of the _end_ of that row in the buffer).
|
||||
if (positionInfo.has_value())
|
||||
{
|
||||
if (!foundOldMutable)
|
||||
// See the comment marked with "REFLOW_RESET".
|
||||
if (newY >= newHeight)
|
||||
{
|
||||
if (iOldRow >= positionInfo.value().get().mutableViewportTop)
|
||||
newRow.Reset(newBuffer._initialAttributes);
|
||||
}
|
||||
|
||||
newRow.CopyFrom(oldRow);
|
||||
newRow.SetWrapForced(false);
|
||||
|
||||
if (oldY == oldCursorPos.y)
|
||||
{
|
||||
newCursorPos = { newRow.AdjustToGlyphStart(oldCursorPos.x), newY };
|
||||
}
|
||||
if (oldY >= mutableViewportTop)
|
||||
{
|
||||
positionInfo->mutableViewportTop = newY;
|
||||
mutableViewportTop = til::CoordTypeMax;
|
||||
}
|
||||
if (oldY >= visibleViewportTop)
|
||||
{
|
||||
positionInfo->visibleViewportTop = newY;
|
||||
visibleViewportTop = til::CoordTypeMax;
|
||||
}
|
||||
|
||||
newY++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rows don't store any information for what column the last written character is in.
|
||||
// We simply truncate all trailing whitespace in this implementation.
|
||||
auto oldRowLimit = oldRow.MeasureRight();
|
||||
if (oldY == oldCursorPos.y)
|
||||
{
|
||||
// REFLOW_JANK_CURSOR_WRAP:
|
||||
// Pretending as if there's always at least whitespace in front of the cursor has the benefit that
|
||||
// * the cursor retains its distance from any preceding text.
|
||||
// * when a client application starts writing on this new, empty line,
|
||||
// enlarging the buffer unwraps the text onto the preceding line.
|
||||
oldRowLimit = std::max(oldRowLimit, oldCursorPos.x + 1);
|
||||
}
|
||||
|
||||
til::CoordType oldX = 0;
|
||||
|
||||
// Copy oldRow into newBuffer until oldRow has been fully consumed.
|
||||
// We use a do-while loop to ensure that line wrapping occurs and
|
||||
// that attributes are copied over even for seemingly empty rows.
|
||||
do
|
||||
{
|
||||
// This if condition handles line wrapping.
|
||||
// Only if we write past the last column we should wrap and as such this if
|
||||
// condition is in front of the text insertion code instead of behind it.
|
||||
// A SetWrapForced of false implies an explicit newline, which is the default.
|
||||
if (newX >= newWidth)
|
||||
{
|
||||
newBuffer.GetMutableRowByOffset(newY).SetWrapForced(true);
|
||||
newX = 0;
|
||||
newY++;
|
||||
}
|
||||
|
||||
// REFLOW_RESET:
|
||||
// If we shrink the buffer vertically, for instance from 100 rows to 90 rows, we will write 10 rows in the
|
||||
// new buffer twice. We need to reset them before copying text, or otherwise we'll see the previous contents.
|
||||
// We don't need to be smart about this. Reset() is fast and shrinking doesn't occur often.
|
||||
if (newY >= newHeight && newX == 0)
|
||||
{
|
||||
// We need to ensure not to overwrite the row the cursor is on.
|
||||
if (newY >= newYLimit)
|
||||
{
|
||||
positionInfo.value().get().mutableViewportTop = newCursor.GetPosition().y;
|
||||
foundOldMutable = true;
|
||||
break;
|
||||
}
|
||||
newBuffer.GetMutableRowByOffset(newY).Reset(newBuffer._initialAttributes);
|
||||
}
|
||||
|
||||
if (!foundOldVisible)
|
||||
auto& newRow = newBuffer.GetMutableRowByOffset(newY);
|
||||
|
||||
RowCopyTextFromState state{
|
||||
.source = oldRow,
|
||||
.columnBegin = newX,
|
||||
.columnLimit = til::CoordTypeMax,
|
||||
.sourceColumnBegin = oldX,
|
||||
.sourceColumnLimit = oldRowLimit,
|
||||
};
|
||||
newRow.CopyTextFrom(state);
|
||||
|
||||
const auto& oldAttr = oldRow.Attributes();
|
||||
auto& newAttr = newRow.Attributes();
|
||||
const auto attributes = oldAttr.slice(gsl::narrow_cast<uint16_t>(oldX), oldAttr.size());
|
||||
newAttr.replace(gsl::narrow_cast<uint16_t>(newX), newAttr.size(), attributes);
|
||||
newAttr.resize_trailing_extent(newWidthU16);
|
||||
|
||||
if (oldY == oldCursorPos.y && oldCursorPos.x >= oldX)
|
||||
{
|
||||
if (iOldRow >= positionInfo.value().get().visibleViewportTop)
|
||||
{
|
||||
positionInfo.value().get().visibleViewportTop = newCursor.GetPosition().y;
|
||||
foundOldVisible = true;
|
||||
}
|
||||
// In theory AdjustToGlyphStart ensures we don't put the cursor on a trailing wide glyph.
|
||||
// In practice I don't think that this can possibly happen. Better safe than sorry.
|
||||
newCursorPos = { newRow.AdjustToGlyphStart(oldCursorPos.x - oldX + newX), newY };
|
||||
// If there's so much text past the old cursor position that it doesn't fit into new buffer,
|
||||
// then the new cursor position will be "lost", because it's overwritten by unrelated text.
|
||||
// We have two choices how can handle this:
|
||||
// * If the new cursor is at an y < 0, just put the cursor at (0,0)
|
||||
// * Stop writing into the new buffer before we overwrite the new cursor position
|
||||
// This implements the second option. There's no fundamental reason why this is better.
|
||||
newYLimit = newY + newHeight;
|
||||
}
|
||||
if (oldY >= mutableViewportTop)
|
||||
{
|
||||
positionInfo->mutableViewportTop = newY;
|
||||
mutableViewportTop = til::CoordTypeMax;
|
||||
}
|
||||
if (oldY >= visibleViewportTop)
|
||||
{
|
||||
positionInfo->visibleViewportTop = newY;
|
||||
visibleViewportTop = til::CoordTypeMax;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't have a full row to copy, insert a new
|
||||
// line into the new buffer.
|
||||
// Only do so if we were not forced to wrap. If we did
|
||||
// force a word wrap, then the existing line break was
|
||||
// only because we ran out of space.
|
||||
if (iRight < cOldColsTotal && !row.WasWrapForced())
|
||||
oldX = state.sourceColumnEnd;
|
||||
newX = state.columnEnd;
|
||||
} while (oldX < oldRowLimit);
|
||||
|
||||
// If the row had an explicit newline we also need to newline. :)
|
||||
if (!oldRow.WasWrapForced())
|
||||
{
|
||||
if (!fFoundCursorPos && (iRight == cOldCursorPos.x && iOldRow == cOldCursorPos.y))
|
||||
{
|
||||
cNewCursorPos = newCursor.GetPosition();
|
||||
fFoundCursorPos = true;
|
||||
}
|
||||
// Only do this if it's not the final line in the buffer.
|
||||
// On the final line, we want the cursor to sit
|
||||
// where it is done printing for the cursor
|
||||
// adjustment to follow.
|
||||
if (iOldRow < cOldRowsTotal - 1)
|
||||
{
|
||||
newBuffer.NewlineCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are on the final line of the buffer, we have one more check.
|
||||
// We got into this code path because we are at the right most column of a row in the old buffer
|
||||
// that had a hard return (no wrap was forced).
|
||||
// However, as we're inserting, the old row might have just barely fit into the new buffer and
|
||||
// caused a new soft return (wrap was forced) putting the cursor at x=0 on the line just below.
|
||||
// We need to preserve the memory of the hard return at this point by inserting one additional
|
||||
// hard newline, otherwise we've lost that information.
|
||||
// We only do this when the cursor has just barely poured over onto the next line so the hard return
|
||||
// isn't covered by the soft one.
|
||||
// e.g.
|
||||
// The old line was:
|
||||
// |aaaaaaaaaaaaaaaaaaa | with no wrap which means there was a newline after that final a.
|
||||
// The cursor was here ^
|
||||
// And the new line will be:
|
||||
// |aaaaaaaaaaaaaaaaaaa| and show a wrap at the end
|
||||
// | |
|
||||
// ^ and the cursor is now there.
|
||||
// If we leave it like this, we've lost the newline information.
|
||||
// So we insert one more newline so a continued reflow of this buffer by resizing larger will
|
||||
// continue to look as the original output intended with the newline data.
|
||||
// After this fix, it looks like this:
|
||||
// |aaaaaaaaaaaaaaaaaaa| no wrap at the end (preserved hard newline)
|
||||
// | |
|
||||
// ^ and the cursor is now here.
|
||||
const auto coordNewCursor = newCursor.GetPosition();
|
||||
if (coordNewCursor.x == 0 && coordNewCursor.y > 0)
|
||||
{
|
||||
if (newBuffer.GetRowByOffset(coordNewCursor.y - 1).WasWrapForced())
|
||||
{
|
||||
newBuffer.NewlineCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
newX = 0;
|
||||
newY++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2617,85 +2654,40 @@ try
|
||||
// printable character. This is to fix the `color 2f` scenario, where you
|
||||
// change the buffer colors then resize and everything below the last
|
||||
// printable char gets reset. See GH #12567
|
||||
auto newRowY = newCursor.GetPosition().y + 1;
|
||||
const auto newHeight = newBuffer.GetSize().Height();
|
||||
const auto oldHeight = oldBuffer._estimateOffsetOfLastCommittedRow() + 1;
|
||||
for (;
|
||||
iOldRow < oldHeight && newRowY < newHeight;
|
||||
iOldRow++)
|
||||
const auto initializedRowsEnd = oldBuffer._estimateOffsetOfLastCommittedRow() + 1;
|
||||
for (; oldY < initializedRowsEnd && newY < newHeight; oldY++, newY++)
|
||||
{
|
||||
const auto& row = oldBuffer.GetRowByOffset(iOldRow);
|
||||
|
||||
// Optimization: Since all these rows are below the last printable char,
|
||||
// we can reasonably assume that they are filled with just spaces.
|
||||
// That's convenient, we can just copy the attr row from the old buffer
|
||||
// into the new one, and resize the row to match. We'll rely on the
|
||||
// behavior of ATTR_ROW::Resize to trim down when narrower, or extend
|
||||
// the last attr when wider.
|
||||
auto& newRow = newBuffer.GetMutableRowByOffset(newRowY);
|
||||
const auto newWidth = newBuffer.GetLineWidth(newRowY);
|
||||
newRow.TransferAttributes(row.Attributes(), newWidth);
|
||||
|
||||
newRowY++;
|
||||
auto& oldRow = oldBuffer.GetRowByOffset(oldY);
|
||||
auto& newRow = newBuffer.GetMutableRowByOffset(newY);
|
||||
auto& newAttr = newRow.Attributes();
|
||||
newAttr = oldRow.Attributes();
|
||||
newAttr.resize_trailing_extent(newWidthU16);
|
||||
}
|
||||
|
||||
// Since we didn't use IncrementCircularBuffer() we need to compute the proper
|
||||
// _firstRow offset now, in a way that replicates IncrementCircularBuffer().
|
||||
// We need to do the same for newCursorPos.y for basically the same reason.
|
||||
if (newY > newHeight)
|
||||
{
|
||||
newBuffer._firstRow = newY % newHeight;
|
||||
// _firstRow maps from API coordinates that always start at 0,0 in the top left corner of the
|
||||
// terminal's scrollback, to the underlying buffer Y coordinate via `(y + _firstRow) % height`.
|
||||
// Here, we need to un-map the `newCursorPos.y` from the underlying Y coordinate to the API coordinate
|
||||
// and so we do `(y - _firstRow) % height`, but we add `+ newHeight` to avoid getting negative results.
|
||||
newCursorPos.y = (newCursorPos.y - newBuffer._firstRow + newHeight) % newHeight;
|
||||
}
|
||||
|
||||
// Finish copying remaining parameters from the old text buffer to the new one
|
||||
newBuffer.CopyProperties(oldBuffer);
|
||||
newBuffer.CopyHyperlinkMaps(oldBuffer);
|
||||
|
||||
// If we found where to put the cursor while placing characters into the buffer,
|
||||
// just put the cursor there. Otherwise we have to advance manually.
|
||||
if (fFoundCursorPos)
|
||||
{
|
||||
newCursor.SetPosition(cNewCursorPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Advance the cursor to the same offset as before
|
||||
// get the number of newlines and spaces between the old end of text and the old cursor,
|
||||
// then advance that many newlines and chars
|
||||
auto iNewlines = cOldCursorPos.y - cOldLastChar.y;
|
||||
const auto iIncrements = cOldCursorPos.x - cOldLastChar.x;
|
||||
const auto cNewLastChar = newBuffer.GetLastNonSpaceCharacter();
|
||||
|
||||
// If the last row of the new buffer wrapped, there's going to be one less newline needed,
|
||||
// because the cursor is already on the next line
|
||||
if (newBuffer.GetRowByOffset(cNewLastChar.y).WasWrapForced())
|
||||
{
|
||||
iNewlines = std::max(iNewlines - 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if this buffer didn't wrap, but the old one DID, then the d(columns) of the
|
||||
// old buffer will be one more than in this buffer, so new need one LESS.
|
||||
if (oldBuffer.GetRowByOffset(cOldLastChar.y).WasWrapForced())
|
||||
{
|
||||
iNewlines = std::max(iNewlines - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto r = 0; r < iNewlines; r++)
|
||||
{
|
||||
newBuffer.NewlineCursor();
|
||||
}
|
||||
for (auto c = 0; c < iIncrements - 1; c++)
|
||||
{
|
||||
newBuffer.IncrementCursor();
|
||||
}
|
||||
}
|
||||
|
||||
// Save old cursor size before we delete it
|
||||
const auto ulSize = oldCursor.GetSize();
|
||||
|
||||
// Set size back to real size as it will be taking over the rendering duties.
|
||||
newCursor.SetSize(ulSize);
|
||||
assert(newCursorPos.x >= 0 && newCursorPos.x < newWidth);
|
||||
assert(newCursorPos.y >= 0 && newCursorPos.y < newHeight);
|
||||
newCursor.SetSize(oldCursor.GetSize());
|
||||
newCursor.SetPosition(newCursorPos);
|
||||
|
||||
newBuffer._marks = oldBuffer._marks;
|
||||
newBuffer._trimMarksOutsideBuffer();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
// Method Description:
|
||||
// - Adds or updates a hyperlink in our hyperlink table
|
||||
@@ -2916,14 +2908,10 @@ void TextBuffer::AddMark(const ScrollMark& m)
|
||||
|
||||
void TextBuffer::_trimMarksOutsideBuffer()
|
||||
{
|
||||
const auto height = GetSize().Height();
|
||||
_marks.erase(std::remove_if(_marks.begin(),
|
||||
_marks.end(),
|
||||
[height](const auto& m) {
|
||||
return (m.start.y < 0) ||
|
||||
(m.start.y >= height);
|
||||
}),
|
||||
_marks.end());
|
||||
const til::CoordType height = _height;
|
||||
std::erase_if(_marks, [height](const auto& m) {
|
||||
return (m.start.y < 0) || (m.start.y >= height);
|
||||
});
|
||||
}
|
||||
|
||||
std::wstring_view TextBuffer::CurrentCommand() const
|
||||
|
||||
@@ -137,6 +137,7 @@ public:
|
||||
|
||||
static size_t GraphemeNext(const std::wstring_view& chars, size_t position) noexcept;
|
||||
static size_t GraphemePrev(const std::wstring_view& chars, size_t position) noexcept;
|
||||
static size_t FitTextIntoColumns(const std::wstring_view& chars, til::CoordType columnLimit, til::CoordType& columns) noexcept;
|
||||
|
||||
til::point NavigateCursor(til::point position, til::CoordType distance) const;
|
||||
|
||||
@@ -163,7 +164,7 @@ public:
|
||||
// Scroll needs access to this to quickly rotate around the buffer.
|
||||
void IncrementCircularBuffer(const TextAttribute& fillAttributes = {});
|
||||
|
||||
til::point GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional = std::nullopt) const;
|
||||
til::point GetLastNonSpaceCharacter(const Microsoft::Console::Types::Viewport* viewOptional = nullptr) const;
|
||||
|
||||
Cursor& GetCursor() noexcept;
|
||||
const Cursor& GetCursor() const noexcept;
|
||||
@@ -194,7 +195,7 @@ public:
|
||||
|
||||
void Reset() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT ResizeTraditional(const til::size newSize) noexcept;
|
||||
void ResizeTraditional(const til::size newSize);
|
||||
|
||||
void SetAsActiveBuffer(const bool isActiveBuffer) noexcept;
|
||||
bool IsActiveBuffer() const noexcept;
|
||||
@@ -262,10 +263,7 @@ public:
|
||||
til::CoordType visibleViewportTop{ 0 };
|
||||
};
|
||||
|
||||
static HRESULT Reflow(TextBuffer& oldBuffer,
|
||||
TextBuffer& newBuffer,
|
||||
const std::optional<Microsoft::Console::Types::Viewport> lastCharacterViewport,
|
||||
std::optional<std::reference_wrapper<PositionInformation>> positionInfo);
|
||||
static void Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const Microsoft::Console::Types::Viewport* lastCharacterViewport = nullptr, PositionInformation* positionInfo = nullptr);
|
||||
|
||||
std::vector<til::point_span> SearchText(const std::wstring_view& needle, bool caseInsensitive) const;
|
||||
std::vector<til::point_span> SearchText(const std::wstring_view& needle, bool caseInsensitive, til::CoordType rowBeg, til::CoordType rowEnd) const;
|
||||
|
||||
@@ -46,8 +46,6 @@ namespace
|
||||
std::vector<TestBuffer> buffers;
|
||||
};
|
||||
|
||||
static constexpr auto true_due_to_exact_wrap_bug{ true };
|
||||
|
||||
static const TestCase testCases[] = {
|
||||
TestCase{
|
||||
L"No reflow required",
|
||||
@@ -61,7 +59,7 @@ namespace
|
||||
{ L"EFG ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
@@ -72,7 +70,7 @@ namespace
|
||||
{ L"EFG ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 4, 5 },
|
||||
@@ -83,7 +81,7 @@ namespace
|
||||
{ L"EFG ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -99,40 +97,40 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
{
|
||||
{ L"ABCDE", true },
|
||||
{ L"F$ ", false }, // [BUG] EXACT WRAP. $ should be alone on next line.
|
||||
{ L" ", false },
|
||||
{ L"F ", false },
|
||||
{ L"$ ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 1, 1 } // cursor on $
|
||||
{ 0, 2 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 6, 5 }, // grow width back to original
|
||||
{
|
||||
{ L"ABCDEF", true_due_to_exact_wrap_bug },
|
||||
{ L"ABCDEF", false },
|
||||
{ L"$ ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 7, 5 }, // grow width wider than original
|
||||
{
|
||||
{ L"ABCDEF$", true_due_to_exact_wrap_bug }, // EXACT WRAP BUG: $ should be alone on next line
|
||||
{ L" ", false },
|
||||
{ L"ABCDEF ", false },
|
||||
{ L"$ ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 6, 0 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -148,7 +146,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 1, 1 } // cursor on $
|
||||
{ 1, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
@@ -159,7 +157,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 2, 1 } // cursor on $
|
||||
{ 2, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 6, 5 }, // grow width back to original
|
||||
@@ -170,7 +168,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 1, 1 } // cursor on $
|
||||
{ 1, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 7, 5 }, // grow width wider than original
|
||||
@@ -181,7 +179,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -197,29 +195,29 @@ namespace
|
||||
{ L"EFG ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 7, 5 }, // reduce width by 1
|
||||
{
|
||||
{ L"AB $", true },
|
||||
{ L" CD", true_due_to_exact_wrap_bug },
|
||||
{ L" ", false },
|
||||
{ L" CD", false }, // CD ends with a newline -> .wrap = false
|
||||
{ L"EFG ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 6, 0 } // cursor on $
|
||||
{ 6, 0 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 8, 5 },
|
||||
{
|
||||
{ L"AB $ ", true },
|
||||
{ L" CD ", false }, // Goes to false because we hit the end of ..CD
|
||||
{ L"EFG ", false }, // [BUG] EFG moves up due to exact wrap bug above
|
||||
{ L" CD ", false },
|
||||
{ L"EFG ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 6, 0 } // cursor on $
|
||||
{ 6, 0 }, // cursor on $
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -236,19 +234,19 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 2, 1 } // cursor on $
|
||||
{ 2, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
{
|
||||
//--012345--
|
||||
{ L"カタ ", true }, // KA TA [FORCED SPACER]
|
||||
{ L"カナ$", true_due_to_exact_wrap_bug }, // KA NA
|
||||
{ L"カナ$", false }, // KA NA
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 4, 1 } // cursor on $
|
||||
{ 4, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 6, 5 }, // grow width back to original
|
||||
@@ -260,7 +258,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 2, 1 } // cursor on $
|
||||
{ 2, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 7, 5 }, // grow width wider than original (by one; no visible change!)
|
||||
@@ -272,7 +270,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 2, 1 } // cursor on $
|
||||
{ 2, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 8, 5 }, // grow width enough to fit second DBCS
|
||||
@@ -284,7 +282,7 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -300,41 +298,29 @@ namespace
|
||||
{ L"MNOPQR", false },
|
||||
{ L"STUVWX", false },
|
||||
},
|
||||
{ 0, 1 } // cursor on $
|
||||
{ 0, 1 }, // cursor on $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
{
|
||||
{ L"F$ ", false },
|
||||
{ L"GHIJK", true }, // [BUG] We should see GHIJK\n L\n MNOPQ\n R\n
|
||||
{ L"LMNOP", true }, // The wrapping here is irregular
|
||||
{ L"QRSTU", true },
|
||||
{ L"VWX ", false },
|
||||
{ L"$ ", false },
|
||||
{ L"GHIJK", true },
|
||||
{ L"L ", false },
|
||||
{ L"MNOPQ", true },
|
||||
{ L"R ", false },
|
||||
},
|
||||
{ 1, 1 } // [BUG] cursor moves to 1,1 instead of sticking with the $
|
||||
{ 0, 0 },
|
||||
},
|
||||
TestBuffer{
|
||||
{ 6, 5 }, // going back to 6,5, the data lost has been destroyed
|
||||
{
|
||||
//{ L"F$ ", false }, // [BUG] this line is erroneously destroyed too!
|
||||
{ L"GHIJKL", true },
|
||||
{ L"MNOPQR", true },
|
||||
{ L"STUVWX", true },
|
||||
{ L"$ ", false },
|
||||
{ L"GHIJKL", false },
|
||||
{ L"MNOPQR", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false }, // [BUG] this line is added
|
||||
},
|
||||
{ 1, 1 }, // [BUG] cursor does not follow [H], it sticks at 1,1
|
||||
},
|
||||
TestBuffer{
|
||||
{ 7, 5 }, // a number of errors are carried forward from the previous buffer
|
||||
{
|
||||
{ L"GHIJKLM", true },
|
||||
{ L"NOPQRST", true },
|
||||
{ L"UVWX ", false }, // [BUG] This line loses wrap for some reason
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 0, 1 }, // [BUG] The cursor moves to 0, 1 now, sticking with the [N] from before
|
||||
{ 0, 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -353,18 +339,18 @@ namespace
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 1, 1 } // cursor *after* $
|
||||
{ 1, 1 }, // cursor *after* $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
{
|
||||
{ L"ABCDE", true },
|
||||
{ L"F$ ", false }, // [BUG] EXACT WRAP. $ should be alone on next line.
|
||||
{ L" ", false },
|
||||
{ L"F ", false },
|
||||
{ L"$ ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 2, 1 } // cursor follows space after $ to next line
|
||||
{ 1, 2 }, // cursor follows space after $ to next line
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -380,7 +366,7 @@ namespace
|
||||
{ L"STUVWX", true },
|
||||
{ L"YZ0 $ ", false },
|
||||
},
|
||||
{ 5, 4 } // cursor *after* $
|
||||
{ 5, 4 }, // cursor *after* $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
@@ -391,7 +377,7 @@ namespace
|
||||
{ L"UVWXY", true },
|
||||
{ L"Z0 $ ", false },
|
||||
},
|
||||
{ 4, 4 } // cursor follows space after $ to newly introduced bottom line
|
||||
{ 4, 4 }, // cursor follows space after $ to newly introduced bottom line
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -402,40 +388,36 @@ namespace
|
||||
{ 6, 5 },
|
||||
{
|
||||
{ L"ABCDEF", false },
|
||||
// v cursor
|
||||
{ L"$ ", false },
|
||||
// ^ cursor
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 5, 1 } // cursor in space far after $
|
||||
{ 5, 1 }, // The cursor is 5 columns to the right of the $ (last column).
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
{
|
||||
{ L"ABCDE", true },
|
||||
{ L"F$ ", true }, // [BUG] This line is marked wrapped, and I do not know why
|
||||
// v cursor
|
||||
{ L" ", false },
|
||||
// ^ cursor
|
||||
{ L"F ", false },
|
||||
// The reflow implementation marks a wrapped cursor as a forced row-wrap (= the row is padded with whitespace), so that when
|
||||
// the buffer is enlarged again, we restore the original cursor position correctly. That's why it says .cursor={5,1} below.
|
||||
{ L"$ ", true },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 1, 2 } // cursor stays same linear distance from $
|
||||
{ 0, 3 }, // $ is now at 0,2 and the cursor used to be 5 columns to the right. -> 0,3
|
||||
},
|
||||
TestBuffer{
|
||||
{ 6, 5 }, // grow back to original size
|
||||
{
|
||||
{ L"ABCDEF", true_due_to_exact_wrap_bug },
|
||||
// v cursor [BUG] cursor does not retain linear distance from $
|
||||
{ L"ABCDEF", false },
|
||||
{ L"$ ", false },
|
||||
// ^ cursor
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 4, 1 } // cursor stays same linear distance from $
|
||||
{ 5, 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -446,39 +428,37 @@ namespace
|
||||
{ 6, 5 },
|
||||
{
|
||||
{ L"ABCDEF", false },
|
||||
// v cursor
|
||||
{ L"$ ", false },
|
||||
// ^ cursor
|
||||
{ L"BLAH ", false },
|
||||
{ L"BLAH ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 5, 1 } // cursor in space far after $
|
||||
{ 5, 1 }, // The cursor is 5 columns to the right of the $ (last column).
|
||||
},
|
||||
TestBuffer{
|
||||
{ 5, 5 }, // reduce width by 1
|
||||
{
|
||||
{ L"ABCDE", true },
|
||||
{ L"F$ ", false },
|
||||
{ L"BLAH ", false },
|
||||
{ L"BLAH ", true }, // [BUG] this line wraps, no idea why
|
||||
// v cursor [BUG] cursor erroneously moved to end of all content
|
||||
{ L"F ", false },
|
||||
// The reflow implementation pads the row with the cursor with whitespace.
|
||||
// Search for "REFLOW_JANK_CURSOR_WRAP" to find the corresponding code.
|
||||
{ L"$ ", true },
|
||||
{ L" ", false },
|
||||
// ^ cursor
|
||||
{ L"BLAH ", false },
|
||||
{ L"BLAH ", false },
|
||||
},
|
||||
{ 0, 4 } },
|
||||
{ 0, 2 },
|
||||
},
|
||||
TestBuffer{
|
||||
{ 6, 5 }, // grow back to original size
|
||||
{
|
||||
{ L"ABCDEF", true },
|
||||
{ L"F ", false },
|
||||
{ L"$ ", false },
|
||||
{ L"BLAH ", false },
|
||||
// v cursor [BUG] cursor is pulled up to previous line because it was marked wrapped
|
||||
{ L"BLAH ", false },
|
||||
// ^ cursor
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 5, 3 } },
|
||||
{ 5, 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
TestCase{
|
||||
@@ -489,27 +469,24 @@ namespace
|
||||
{ 6, 5 },
|
||||
{
|
||||
{ L"ABCDEF", false },
|
||||
// v cursor
|
||||
{ L"$ ", false },
|
||||
// ^ cursor
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
{ L" ", false },
|
||||
},
|
||||
{ 5, 1 } // cursor in space far after $
|
||||
{ 5, 1 }, // The cursor is 5 columns to the right of the $ (last column).
|
||||
},
|
||||
TestBuffer{
|
||||
{ 2, 5 }, // reduce width aggressively
|
||||
{
|
||||
{ L"CD", true },
|
||||
{ L"EF", true },
|
||||
{ L"EF", false },
|
||||
{ L"$ ", true },
|
||||
{ L" ", true },
|
||||
// v cursor
|
||||
{ L" ", false },
|
||||
// ^ cursor
|
||||
},
|
||||
{ 1, 4 } },
|
||||
{ 1, 4 },
|
||||
},
|
||||
},
|
||||
},
|
||||
TestCase{
|
||||
@@ -519,27 +496,24 @@ namespace
|
||||
{ 6, 5 },
|
||||
{
|
||||
{ L"ABCDEF", true },
|
||||
// v cursor
|
||||
{ L"$ ", true },
|
||||
// ^ cursor
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
},
|
||||
{ 5, 1 } // cursor in space far after $
|
||||
{ 5, 1 }, // cursor in space far after $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 2, 5 }, // reduce width aggressively
|
||||
{
|
||||
{ L"EF", true },
|
||||
{ L"$ ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
// v cursor [BUG] cursor does not maintain linear distance from $
|
||||
{ L" ", false },
|
||||
// ^ cursor
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
},
|
||||
{ 1, 4 } },
|
||||
{ 1, 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
TestCase{
|
||||
@@ -549,14 +523,12 @@ namespace
|
||||
{ 6, 5 },
|
||||
{
|
||||
{ L"ABCDEF", true },
|
||||
// v cursor
|
||||
{ L"$ ", true },
|
||||
// ^ cursor
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" Q", true },
|
||||
},
|
||||
{ 5, 1 } // cursor in space far after $
|
||||
{ 5, 1 }, // cursor in space far after $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 2, 5 }, // reduce width aggressively
|
||||
@@ -564,12 +536,11 @@ namespace
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" Q", true },
|
||||
// v cursor [BUG] cursor jumps to end of world
|
||||
{ L" ", false }, // POTENTIAL [BUG] a whole new blank line is added for the cursor
|
||||
// ^ cursor
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
},
|
||||
{ 1, 4 } },
|
||||
{ 1, 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
TestCase{
|
||||
@@ -579,27 +550,24 @@ namespace
|
||||
{ 6, 5 },
|
||||
{
|
||||
{ L"ABCDEF", false },
|
||||
// v cursor
|
||||
{ L"$ ", false },
|
||||
// ^ cursor
|
||||
{ L" ", false },
|
||||
{ L" ", true },
|
||||
{ L" Q", true },
|
||||
},
|
||||
{ 5, 1 } // cursor in space far after $
|
||||
{ 5, 1 }, // cursor in space far after $
|
||||
},
|
||||
TestBuffer{
|
||||
{ 2, 5 }, // reduce width aggressively
|
||||
{
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" Q", true },
|
||||
// v cursor [BUG] cursor jumps to different place than fully wrapped case
|
||||
{ L" ", false },
|
||||
// ^ cursor
|
||||
{ L" ", false },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
},
|
||||
{ 0, 4 } },
|
||||
{ 1, 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
TestCase{
|
||||
@@ -614,24 +582,21 @@ namespace
|
||||
{ L"$ ", false },
|
||||
{ L" Q", true },
|
||||
{ L" ", true },
|
||||
// v cursor
|
||||
{ L" ", true },
|
||||
// ^ cursor
|
||||
},
|
||||
{ 5, 4 } // cursor at end of buffer
|
||||
{ 5, 4 }, // cursor at end of buffer
|
||||
},
|
||||
TestBuffer{
|
||||
{ 2, 5 }, // reduce width aggressively
|
||||
{
|
||||
{ L" ", false },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" ", true },
|
||||
{ L" Q", true },
|
||||
{ L" ", false },
|
||||
// v cursor [BUG] cursor loses linear distance from Q; is this important?
|
||||
{ L" ", false },
|
||||
// ^ cursor
|
||||
},
|
||||
{ 0, 4 } },
|
||||
{ 1, 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -761,7 +726,7 @@ class ReflowTests
|
||||
static std::unique_ptr<TextBuffer> _textBufferByReflowingTextBuffer(TextBuffer& originalBuffer, const til::size newSize)
|
||||
{
|
||||
auto buffer = std::make_unique<TextBuffer>(newSize, TextAttribute{ 0x7 }, 0, false, renderer);
|
||||
TextBuffer::Reflow(originalBuffer, *buffer, std::nullopt, std::nullopt);
|
||||
TextBuffer::Reflow(originalBuffer, *buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<ClCompile Include="ReflowTests.cpp" />
|
||||
<ClCompile Include="TextColorTests.cpp" />
|
||||
<ClCompile Include="TextAttributeTests.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<ClCompile Include="precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@@ -30,7 +30,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="precomp.h" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
|
||||
@@ -7,17 +7,18 @@
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">
|
||||
|
||||
<Identity
|
||||
Name="WindowsTerminalCan"
|
||||
Name="Microsoft.WindowsTerminalCanary"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="0.0.1.0" />
|
||||
|
||||
@@ -33,10 +34,13 @@
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<!-- rescap:appLicensing only works on 22000+. Until that's fixed, MinVersion will not let people install it on Windows 10... -->
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.22000.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.22000.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
@@ -72,17 +76,17 @@
|
||||
<desktop:ExecutionAlias Alias="wt.exe" />
|
||||
</uap3:AppExecutionAlias>
|
||||
</uap3:Extension>
|
||||
<uap3:Extension Category="windows.appExtensionHost">
|
||||
<uap3:AppExtensionHost>
|
||||
<uap3:Name>com.microsoft.windows.terminal.settings</uap3:Name>
|
||||
</uap3:AppExtensionHost>
|
||||
</uap3:Extension>
|
||||
<uap5:Extension Category="windows.startupTask">
|
||||
<uap5:StartupTask
|
||||
TaskId="StartTerminalOnLoginTask"
|
||||
Enabled="false"
|
||||
DisplayName="ms-resource:AppNameCan" />
|
||||
</uap5:Extension>
|
||||
<uap3:Extension Category="windows.appExtensionHost">
|
||||
<uap3:AppExtensionHost>
|
||||
<uap3:Name>com.microsoft.windows.terminal.settings</uap3:Name>
|
||||
</uap3:AppExtensionHost>
|
||||
</uap3:Extension>
|
||||
<uap3:Extension Category="windows.appExtension">
|
||||
<uap3:AppExtension Name="com.microsoft.windows.console.host"
|
||||
Id="OpenConsole-Can"
|
||||
@@ -90,7 +94,7 @@
|
||||
Description="Console host built from microsoft/terminal open source repository"
|
||||
PublicFolder="Public">
|
||||
<uap3:Properties>
|
||||
<Clsid>{1F9F2BF5-5BC3-4F17-B0E6-912413F1F451}</Clsid>
|
||||
<Clsid>{A854D02A-F2FE-44A5-BB24-D03F4CF830D4}</Clsid>
|
||||
</uap3:Properties>
|
||||
</uap3:AppExtension>
|
||||
</uap3:Extension>
|
||||
@@ -101,7 +105,7 @@
|
||||
Description="Terminal host built from microsoft/terminal open source repository"
|
||||
PublicFolder="Public">
|
||||
<uap3:Properties>
|
||||
<Clsid>{051F34EE-C1FD-4B19-AF75-9BA54648434C}</Clsid>
|
||||
<Clsid>{1706609C-A4CE-4C0D-B7D2-C19BF66398A5}</Clsid>
|
||||
</uap3:Properties>
|
||||
</uap3:AppExtension>
|
||||
</uap3:Extension>
|
||||
@@ -147,5 +151,10 @@
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
<rescap:Capability Name="appLicensing" />
|
||||
</Capabilities>
|
||||
|
||||
<mp:PhoneIdentity
|
||||
PhoneProductId="348ff861-8d83-47b2-a740-15f8a096dcae"
|
||||
PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
</Package>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
@@ -14,7 +15,7 @@
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">
|
||||
|
||||
<Identity
|
||||
Name="WindowsTerminalDev"
|
||||
@@ -33,10 +34,12 @@
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7"
|
||||
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">
|
||||
|
||||
<Identity
|
||||
Name="Microsoft.WindowsTerminalPreview"
|
||||
@@ -34,10 +35,12 @@
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7"
|
||||
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">
|
||||
|
||||
<Identity
|
||||
Name="Microsoft.WindowsTerminal"
|
||||
@@ -34,10 +35,12 @@
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -74,6 +74,8 @@ namespace SettingsModelLocalTests
|
||||
TEST_METHOD(TestInheritedCommand);
|
||||
TEST_METHOD(LoadFragmentsWithMultipleUpdates);
|
||||
|
||||
TEST_METHOD(MigrateReloadEnvVars);
|
||||
|
||||
private:
|
||||
static winrt::com_ptr<implementation::CascadiaSettings> createSettings(const std::string_view& userJSON)
|
||||
{
|
||||
@@ -2020,4 +2022,40 @@ namespace SettingsModelLocalTests
|
||||
// GH#12520: Fragments should be able to override the name of builtin profiles.
|
||||
VERIFY_ARE_EQUAL(L"NewName", loader.userSettings.profiles[0]->Name());
|
||||
}
|
||||
|
||||
void DeserializationTests::MigrateReloadEnvVars()
|
||||
{
|
||||
static constexpr std::string_view settings1Json{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"compatibility.reloadEnvironmentVariables": false,
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"name": "foo",
|
||||
"command": "closePane",
|
||||
"keys": "ctrl+shift+w"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
|
||||
implementation::SettingsLoader loader{ settings1Json, DefaultJson };
|
||||
loader.MergeInboxIntoUserSettings();
|
||||
loader.FinalizeLayering();
|
||||
|
||||
VERIFY_IS_TRUE(loader.FixupUserSettings(), L"Validate that this will indicate we need to write them back to disk");
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(std::move(loader));
|
||||
|
||||
Log::Comment(L"Ensure that the profile defaults have the new setting added");
|
||||
VERIFY_IS_TRUE(settings->ProfileDefaults().HasReloadEnvironmentVariables());
|
||||
VERIFY_IS_FALSE(settings->ProfileDefaults().ReloadEnvironmentVariables());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ namespace SettingsModelLocalTests
|
||||
TEST_METHOD(CascadiaSettings);
|
||||
TEST_METHOD(LegacyFontSettings);
|
||||
|
||||
TEST_METHOD(RoundtripReloadEnvVars);
|
||||
TEST_METHOD(DontRoundtripNoReloadEnvVars);
|
||||
|
||||
private:
|
||||
// Method Description:
|
||||
// - deserializes and reserializes a json string representing a settings object model of type T
|
||||
@@ -513,4 +516,114 @@ namespace SettingsModelLocalTests
|
||||
|
||||
VERIFY_ARE_EQUAL(toString(jsonOutput), toString(result));
|
||||
}
|
||||
|
||||
void SerializationTests::RoundtripReloadEnvVars()
|
||||
{
|
||||
static constexpr std::string_view oldSettingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"compatibility.reloadEnvironmentVariables": false,
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"name": "foo",
|
||||
"command": "closePane",
|
||||
"keys": "ctrl+shift+w"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
|
||||
static constexpr std::string_view newSettingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles":
|
||||
{
|
||||
"defaults":
|
||||
{
|
||||
"compatibility.reloadEnvironmentVariables": false
|
||||
},
|
||||
"list":
|
||||
[
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
]
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"name": "foo",
|
||||
"command": "closePane",
|
||||
"keys": "ctrl+shift+w"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
|
||||
implementation::SettingsLoader oldLoader{ oldSettingsJson, DefaultJson };
|
||||
oldLoader.MergeInboxIntoUserSettings();
|
||||
oldLoader.FinalizeLayering();
|
||||
VERIFY_IS_TRUE(oldLoader.FixupUserSettings(), L"Validate that this will indicate we need to write them back to disk");
|
||||
const auto oldSettings = winrt::make_self<implementation::CascadiaSettings>(std::move(oldLoader));
|
||||
const auto oldResult{ oldSettings->ToJson() };
|
||||
|
||||
implementation::SettingsLoader newLoader{ newSettingsJson, DefaultJson };
|
||||
newLoader.MergeInboxIntoUserSettings();
|
||||
newLoader.FinalizeLayering();
|
||||
newLoader.FixupUserSettings();
|
||||
const auto newSettings = winrt::make_self<implementation::CascadiaSettings>(std::move(newLoader));
|
||||
const auto newResult{ newSettings->ToJson() };
|
||||
|
||||
VERIFY_ARE_EQUAL(toString(newResult), toString(oldResult));
|
||||
}
|
||||
|
||||
void SerializationTests::DontRoundtripNoReloadEnvVars()
|
||||
{
|
||||
// Kinda like the above test, but confirming that _nothing_ happens if
|
||||
// we don't have a setting to migrate.
|
||||
|
||||
static constexpr std::string_view oldSettingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"name": "foo",
|
||||
"command": "closePane",
|
||||
"keys": "ctrl+shift+w"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
|
||||
implementation::SettingsLoader oldLoader{ oldSettingsJson, DefaultJson };
|
||||
oldLoader.MergeInboxIntoUserSettings();
|
||||
oldLoader.FinalizeLayering();
|
||||
oldLoader.FixupUserSettings();
|
||||
const auto oldSettings = winrt::make_self<implementation::CascadiaSettings>(std::move(oldLoader));
|
||||
const auto oldResult{ oldSettings->ToJson() };
|
||||
|
||||
Log::Comment(L"Now, create a _new_ settings object from the re-serialization of the first");
|
||||
implementation::SettingsLoader newLoader{ toString(oldResult), DefaultJson };
|
||||
newLoader.MergeInboxIntoUserSettings();
|
||||
newLoader.FinalizeLayering();
|
||||
newLoader.FixupUserSettings();
|
||||
const auto newSettings = winrt::make_self<implementation::CascadiaSettings>(std::move(newLoader));
|
||||
VERIFY_IS_FALSE(newSettings->ProfileDefaults().HasReloadEnvironmentVariables(),
|
||||
L"Ensure that the new settings object didn't find a reloadEnvironmentVariables");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace SettingsModelLocalTests
|
||||
"tabRow":
|
||||
{
|
||||
"background": "#FFFF8800",
|
||||
"unfocusedBackground": "#FF8844"
|
||||
"unfocusedBackground": "#FF8844",
|
||||
"iconStyle": "default"
|
||||
},
|
||||
"window":
|
||||
{
|
||||
|
||||
@@ -64,6 +64,7 @@ Author(s):
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
#include <til/winrt.h>
|
||||
|
||||
// Common includes for most tests:
|
||||
#include "../../inc/conattrs.hpp"
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{84848BFA-931D-42CE-9ADF-01EE54DE7890}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>PublicTerminalCore</RootNamespace>
|
||||
<ProjectName>PublicTerminalCore</ProjectName>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.props" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminal.cpp" />
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HwndTerminal.hpp" />
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(SolutionDir)src\terminal\input\lib\terminalinput.vcxproj">
|
||||
<Project>{1cf55140-ef6a-4736-a403-957e4f7430bb}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)src\cascadia\TerminalCore\lib\TerminalCore-lib.vcxproj">
|
||||
<Project>{ca5cad1a-abcd-429c-b551-8562ec954746}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)src\types\lib\types.vcxproj">
|
||||
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)src\renderer\atlas\atlas.vcxproj">
|
||||
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)src\renderer\base\lib\base.vcxproj">
|
||||
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)src\renderer\dx\lib\dx.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf63}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
||||
|
||||
<!-- LATE LINK LINE OVERRIDES. This project must link named forwarders
|
||||
instead of APISet forwarders for easier Windows 7 compatibility. -->
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>delayimp.lib;Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>uiautomationcore.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminal.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HwndTerminal.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // If this is not defined, windows.h includes commdlg.h which defines FindText globally and conflicts with UIAutomation ITextRangeProvider.
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
#endif
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
#include <UIAutomationCore.h>
|
||||
@@ -15,10 +15,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
CommandlineArgs(const winrt::array_view<const winrt::hstring>& args,
|
||||
winrt::hstring currentDirectory,
|
||||
const uint32_t showWindowCommand) :
|
||||
const uint32_t showWindowCommand,
|
||||
winrt::hstring envString) :
|
||||
_args{ args.begin(), args.end() },
|
||||
_cwd{ currentDirectory },
|
||||
_ShowWindowCommand{ showWindowCommand }
|
||||
_ShowWindowCommand{ showWindowCommand },
|
||||
CurrentEnvironment{ envString }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -27,6 +29,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void Commandline(const winrt::array_view<const winrt::hstring>& value);
|
||||
winrt::com_array<winrt::hstring> Commandline();
|
||||
|
||||
til::property<winrt::hstring> CurrentEnvironment;
|
||||
|
||||
WINRT_PROPERTY(uint32_t, ShowWindowCommand, SW_NORMAL); // SW_NORMAL is 1, 0 is SW_HIDE
|
||||
|
||||
private:
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
_WindowName{ windowInfo.WindowName() },
|
||||
_args{ command.Commandline() },
|
||||
_CurrentDirectory{ command.CurrentDirectory() },
|
||||
_ShowWindowCommand{ command.ShowWindowCommand() } {};
|
||||
_ShowWindowCommand{ command.ShowWindowCommand() },
|
||||
_CurrentEnvironment{ command.CurrentEnvironment() } {};
|
||||
|
||||
WindowRequestedArgs(const winrt::hstring& window, const winrt::hstring& content, const Windows::Foundation::IReference<Windows::Foundation::Rect>& bounds) :
|
||||
_Id{ 0u },
|
||||
@@ -68,6 +69,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
WINRT_PROPERTY(winrt::hstring, CurrentDirectory);
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(uint32_t, ShowWindowCommand, SW_NORMAL);
|
||||
WINRT_PROPERTY(winrt::hstring, CurrentEnvironment);
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
|
||||
|
||||
private:
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Microsoft.Terminal.Remoting
|
||||
String[] Commandline { get; };
|
||||
String CurrentDirectory { get; };
|
||||
UInt32 ShowWindowCommand { get; };
|
||||
String CurrentEnvironment { get; };
|
||||
|
||||
String Content { get; };
|
||||
Windows.Foundation.IReference<Windows.Foundation.Rect> InitialBounds { get; };
|
||||
|
||||
@@ -7,11 +7,12 @@ namespace Microsoft.Terminal.Remoting
|
||||
runtimeclass CommandlineArgs
|
||||
{
|
||||
CommandlineArgs();
|
||||
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand);
|
||||
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand, String env);
|
||||
|
||||
String[] Commandline { get; set; };
|
||||
String CurrentDirectory { get; };
|
||||
UInt32 ShowWindowCommand { get; };
|
||||
String CurrentEnvironment { get; };
|
||||
};
|
||||
|
||||
runtimeclass RenameRequestArgs
|
||||
|
||||
@@ -349,7 +349,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// If the name wasn't specified, this will be an empty string.
|
||||
p->WindowName(args.WindowName());
|
||||
|
||||
p->ExecuteCommandline(*winrt::make_self<CommandlineArgs>(args.Commandline(), args.CurrentDirectory(), args.ShowWindowCommand()));
|
||||
p->ExecuteCommandline(*winrt::make_self<CommandlineArgs>(args.Commandline(),
|
||||
args.CurrentDirectory(),
|
||||
args.ShowWindowCommand(),
|
||||
args.CurrentEnvironment()));
|
||||
|
||||
_monarch.AddPeasant(*p);
|
||||
|
||||
|
||||
@@ -52,3 +52,4 @@ TRACELOGGING_DECLARE_PROVIDER(g_hRemotingProvider);
|
||||
#include "til.h"
|
||||
|
||||
#include <cppwinrt_utils.h>
|
||||
#include <til/winrt.h>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user