mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-21 14:27:22 +00:00
Compare commits
100 Commits
v1.24.1132
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dec420eb42 | ||
|
|
2c81220ff9 | ||
|
|
7b93943c38 | ||
|
|
111a6c0c5f | ||
|
|
d4853a8149 | ||
|
|
e13bf07d02 | ||
|
|
0dc09aa5a3 | ||
|
|
3cdd45275c | ||
|
|
68b40c2984 | ||
|
|
32b7c242dd | ||
|
|
949ea5b171 | ||
|
|
ad4f8a2d71 | ||
|
|
ebd9afe233 | ||
|
|
0f1ce90215 | ||
|
|
28e6265275 | ||
|
|
58ddc9a907 | ||
|
|
ff0cbee4fe | ||
|
|
3dcc1c19aa | ||
|
|
8be4ea22a7 | ||
|
|
b678b33d57 | ||
|
|
788e42f482 | ||
|
|
a47bfcc036 | ||
|
|
716cb56505 | ||
|
|
4f1a72ae1c | ||
|
|
faad1b1759 | ||
|
|
abfaa5dc5f | ||
|
|
a2bced81a9 | ||
|
|
72fbcd6559 | ||
|
|
cae559376a | ||
|
|
c6ea72fb61 | ||
|
|
b1306c5e79 | ||
|
|
1735110040 | ||
|
|
aa7681f125 | ||
|
|
0f947043c9 | ||
|
|
0f6d29adaf | ||
|
|
24a8463818 | ||
|
|
c25cd5c9c7 | ||
|
|
78f1bdff69 | ||
|
|
dda7410408 | ||
|
|
07cfad1e35 | ||
|
|
69789eae14 | ||
|
|
daec33babc | ||
|
|
a1879878f0 | ||
|
|
faa4c1ac8b | ||
|
|
d1c7ee2c17 | ||
|
|
377cc05fb7 | ||
|
|
06648e3212 | ||
|
|
acc019b3cb | ||
|
|
8d37b213e2 | ||
|
|
efb7f30717 | ||
|
|
decfc3dcee | ||
|
|
c288df551e | ||
|
|
fc0ad5ab75 | ||
|
|
20b0447774 | ||
|
|
c4130367f3 | ||
|
|
64c774e2a7 | ||
|
|
462192e88b | ||
|
|
062e2b3f20 | ||
|
|
5dcde95bfb | ||
|
|
ecfe4b5d6a | ||
|
|
6027a367b2 | ||
|
|
2f6b546f02 | ||
|
|
eada4d2c9e | ||
|
|
4829e9218e | ||
|
|
edef86b654 | ||
|
|
cd9a114359 | ||
|
|
0b63a33301 | ||
|
|
a0eaea84f0 | ||
|
|
038ad3b509 | ||
|
|
f2a691863b | ||
|
|
76daf71cf9 | ||
|
|
22edbc1b37 | ||
|
|
479f625c36 | ||
|
|
f5aa18a389 | ||
|
|
6933429721 | ||
|
|
7453b159c1 | ||
|
|
dab0c3a010 | ||
|
|
8b9504b536 | ||
|
|
c4e60ad5d6 | ||
|
|
fc50edd5b4 | ||
|
|
531901505c | ||
|
|
b68de3e5c5 | ||
|
|
fff3372ed2 | ||
|
|
f3f9eba5c9 | ||
|
|
b670800460 | ||
|
|
210145a709 | ||
|
|
961925b04f | ||
|
|
b8847a3407 | ||
|
|
a4a12ef190 | ||
|
|
91a60caf41 | ||
|
|
88b527f606 | ||
|
|
976cddbe7c | ||
|
|
93c08bd459 | ||
|
|
ba8171e0a4 | ||
|
|
83e7e14978 | ||
|
|
74e3985ba8 | ||
|
|
9e05dcd4f3 | ||
|
|
81f2d3a834 | ||
|
|
0080b81149 | ||
|
|
2fdcd4e151 |
15
.github/actions/spelling/README.md
vendored
Normal file
15
.github/actions/spelling/README.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# check-spelling/check-spelling configuration
|
||||
|
||||
File | Purpose | Format | Info
|
||||
-|-|-|-
|
||||
[allow/*.txt](allow/) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow)
|
||||
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
|
||||
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
|
||||
[patterns/*.txt](patterns/) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
|
||||
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
|
||||
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
|
||||
[expect/*.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
|
||||
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
|
||||
|
||||
Note: you can replace any of these files with a directory by the same name (minus the suffix)
|
||||
and then include multiple files inside that directory (with that suffix) to merge multiple files together.
|
||||
38
.github/actions/spelling/advice.md
vendored
38
.github/actions/spelling/advice.md
vendored
@@ -1,4 +1,4 @@
|
||||
<!-- markdownlint-disable MD033 MD041 -->
|
||||
<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
|
||||
<details>
|
||||
<summary>
|
||||
:pencil2: Contributor please read this
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
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. You can copy the contents of each `perl` command excluding the outer `'` marks and dropping any `'"`/`"'` quotation mark pairs into a file and then run `perl file.pl` from the root of the repository to run the code. Alternatively, you can manually insert the items...
|
||||
: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:
|
||||
|
||||
@@ -20,31 +20,29 @@ See the `README.md` in each directory for more information.
|
||||
|
||||
:microscope: You can test your commits **without** *appending* to a PR by creating a new branch with that extra change and pushing it to your fork. The [check-spelling](https://github.com/marketplace/actions/check-spelling) action will run in response to your **push** -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. :wink:
|
||||
|
||||
<details><summary>:clamp: If you see a bunch of garbage</summary>
|
||||
|
||||
If it relates to a ...
|
||||
<details><summary>well-formed pattern</summary>
|
||||
<details><summary>If the flagged items are :exploding_head: false positives</summary>
|
||||
|
||||
See if there's a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it.
|
||||
If items relate to a ...
|
||||
* binary file (or some other file you wouldn't want to check at all).
|
||||
|
||||
If not, try writing one and adding it to a `patterns/{file}.txt`.
|
||||
Please add a file path to the `excludes.txt` file matching the containing file.
|
||||
|
||||
Patterns are Perl 5 Regular Expressions - you can [test](
|
||||
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
|
||||
|
||||
Note that patterns can't match multiline strings.
|
||||
</details>
|
||||
<details><summary>binary-ish string</summary>
|
||||
|
||||
Please add a file path to the `excludes.txt` file instead of just accepting the garbage.
|
||||
|
||||
File paths are Perl 5 Regular Expressions - you can [test](
|
||||
File paths are Perl 5 Regular Expressions - you can [test](
|
||||
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
|
||||
|
||||
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
|
||||
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
|
||||
../tree/HEAD/README.md) (on whichever branch you're using).
|
||||
</details>
|
||||
|
||||
|
||||
* well-formed pattern.
|
||||
|
||||
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](
|
||||
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
|
||||
|
||||
Note that patterns can't match multiline strings.
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
20
.github/actions/spelling/allow/allow.txt
vendored
20
.github/actions/spelling/allow/allow.txt
vendored
@@ -1,20 +1,21 @@
|
||||
admins
|
||||
apc
|
||||
allcolors
|
||||
Apc
|
||||
bsd
|
||||
apc
|
||||
breadcrumb
|
||||
breadcrumbs
|
||||
bsd
|
||||
calt
|
||||
CMMI
|
||||
ccmp
|
||||
changelog
|
||||
clickable
|
||||
clig
|
||||
CMMI
|
||||
copyable
|
||||
cybersecurity
|
||||
dalet
|
||||
dcs
|
||||
Dcs
|
||||
dcs
|
||||
dialytika
|
||||
dje
|
||||
downside
|
||||
@@ -33,10 +34,12 @@ gantt
|
||||
gcc
|
||||
geeksforgeeks
|
||||
ghe
|
||||
github
|
||||
gje
|
||||
godbolt
|
||||
hostname
|
||||
hostnames
|
||||
https
|
||||
hyperlink
|
||||
hyperlinking
|
||||
hyperlinks
|
||||
@@ -53,13 +56,14 @@ Llast
|
||||
llvm
|
||||
Lmid
|
||||
locl
|
||||
lol
|
||||
lorem
|
||||
Lorigin
|
||||
maxed
|
||||
minimalistic
|
||||
mkmk
|
||||
mnt
|
||||
mru
|
||||
noreply
|
||||
nje
|
||||
noreply
|
||||
ogonek
|
||||
@@ -80,13 +84,16 @@ runtimes
|
||||
shcha
|
||||
slnt
|
||||
Sos
|
||||
ssh
|
||||
timeline
|
||||
timelines
|
||||
timestamped
|
||||
TLDR
|
||||
tokenizes
|
||||
tonos
|
||||
toolset
|
||||
tshe
|
||||
ubuntu
|
||||
uiatextrange
|
||||
UIs
|
||||
und
|
||||
@@ -95,6 +102,7 @@ versioned
|
||||
vsdevcmd
|
||||
We'd
|
||||
wildcards
|
||||
XBox
|
||||
YBox
|
||||
yeru
|
||||
zhe
|
||||
allcolors
|
||||
|
||||
21
.github/actions/spelling/allow/apis.txt
vendored
21
.github/actions/spelling/allow/apis.txt
vendored
@@ -5,6 +5,7 @@ aclapi
|
||||
alignas
|
||||
alignof
|
||||
APPLYTOSUBMENUS
|
||||
appxrecipe
|
||||
bitfield
|
||||
bitfields
|
||||
BUILDBRANCH
|
||||
@@ -14,6 +15,7 @@ BYCOMMAND
|
||||
BYPOSITION
|
||||
charconv
|
||||
CLASSNOTAVAILABLE
|
||||
CLOSEAPP
|
||||
cmdletbinding
|
||||
COLORPROPERTY
|
||||
colspan
|
||||
@@ -28,9 +30,14 @@ dataobject
|
||||
dcomp
|
||||
DERR
|
||||
dlldata
|
||||
DNE
|
||||
DONTADDTORECENT
|
||||
DWMSBT
|
||||
DWMWA
|
||||
DWMWA
|
||||
DWORDLONG
|
||||
endfor
|
||||
ENDSESSION
|
||||
enumset
|
||||
environstrings
|
||||
EXPCMDFLAGS
|
||||
@@ -70,6 +77,7 @@ IDirect
|
||||
IExplorer
|
||||
IFACEMETHOD
|
||||
IFile
|
||||
IGraphics
|
||||
IInheritable
|
||||
IMap
|
||||
IMonarch
|
||||
@@ -84,6 +92,7 @@ istream
|
||||
IStringable
|
||||
ITab
|
||||
ITaskbar
|
||||
itow
|
||||
IUri
|
||||
IVirtual
|
||||
KEYSELECT
|
||||
@@ -95,12 +104,14 @@ lround
|
||||
Lsa
|
||||
lsass
|
||||
LSHIFT
|
||||
LTGRAY
|
||||
MAINWINDOW
|
||||
memchr
|
||||
memicmp
|
||||
MENUCOMMAND
|
||||
MENUDATA
|
||||
MENUITEMINFOW
|
||||
MENUINFO
|
||||
MENUITEMINFOW
|
||||
mmeapi
|
||||
MOUSELEAVE
|
||||
mov
|
||||
@@ -137,16 +148,18 @@ OUTLINETEXTMETRICW
|
||||
overridable
|
||||
PACL
|
||||
PAGESCROLL
|
||||
PATINVERT
|
||||
PEXPLICIT
|
||||
PICKFOLDERS
|
||||
pmr
|
||||
ptstr
|
||||
QUERYENDSESSION
|
||||
rcx
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
ROOTOWNER
|
||||
roundf
|
||||
RSHIFT
|
||||
SACL
|
||||
schandle
|
||||
@@ -176,6 +189,8 @@ Stubless
|
||||
Subheader
|
||||
Subpage
|
||||
syscall
|
||||
SYSTEMBACKDROP
|
||||
TABROW
|
||||
TASKBARCREATED
|
||||
TBPF
|
||||
THEMECHANGED
|
||||
@@ -195,6 +210,8 @@ UOI
|
||||
UPDATEINIFILE
|
||||
userenv
|
||||
USEROBJECTFLAGS
|
||||
Viewbox
|
||||
virtualalloc
|
||||
wcsstr
|
||||
wcstoui
|
||||
winmain
|
||||
|
||||
2
.github/actions/spelling/allow/names.txt
vendored
2
.github/actions/spelling/allow/names.txt
vendored
@@ -69,6 +69,8 @@ Rincewind
|
||||
rprichard
|
||||
Schoonover
|
||||
shadertoy
|
||||
Shomnipotence
|
||||
simioni
|
||||
Somuah
|
||||
sonph
|
||||
sonpham
|
||||
|
||||
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
# 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.*$
|
||||
|
||||
# patch hunk comments
|
||||
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
|
||||
# git index header
|
||||
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
|
||||
|
||||
# cid urls
|
||||
(['"])cid:.*?\g{-1}
|
||||
|
||||
# data url in parens
|
||||
\(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 url
|
||||
data:[-a-zA-Z=;:/0-9+]*,\S*
|
||||
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
# magnet urls
|
||||
magnet:[?=:\w]+
|
||||
|
||||
# magnet urls
|
||||
"magnet:[^"]+"
|
||||
|
||||
# obs:
|
||||
"obs:[^"]*"
|
||||
|
||||
# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read
|
||||
# In this examples content, I'm using a number of different ways to match things to show various approaches
|
||||
# asciinema
|
||||
\basciinema\.org/a/[0-9a-zA-Z]+
|
||||
|
||||
# apple
|
||||
\bdeveloper\.apple\.com/[-\w?=/]+
|
||||
# Apple music
|
||||
\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+
|
||||
|
||||
# appveyor api
|
||||
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
|
||||
# appveyor project
|
||||
\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+
|
||||
|
||||
# Amazon
|
||||
|
||||
# Amazon
|
||||
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
|
||||
# AWS S3
|
||||
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
|
||||
# AWS execute-api
|
||||
\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b
|
||||
# AWS ELB
|
||||
\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b
|
||||
# AWS SNS
|
||||
\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]*
|
||||
# AWS VPC
|
||||
vpc-\w+
|
||||
|
||||
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
|
||||
# YouTube url
|
||||
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
|
||||
# YouTube music
|
||||
\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*)
|
||||
# YouTube tag
|
||||
<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"]
|
||||
# YouTube image
|
||||
\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]*
|
||||
# Google Accounts
|
||||
\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]*
|
||||
# Google Analytics
|
||||
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
|
||||
# Google APIs
|
||||
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
|
||||
# Google Storage
|
||||
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
|
||||
# Google Calendar
|
||||
\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+
|
||||
\w+\@group\.calendar\.google\.com\b
|
||||
# Google DataStudio
|
||||
\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|)
|
||||
# The leading `/` here is as opposed to the `\b` above
|
||||
# ... a short way to match `https://` or `http://` since most urls have one of those prefixes
|
||||
# Google Docs
|
||||
/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\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]+)*
|
||||
# Google Maps
|
||||
\bmaps\.google\.com/maps\?[\w&;=]*
|
||||
# Google themes
|
||||
themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
|
||||
# Google CDN
|
||||
\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]*
|
||||
# Goo.gl
|
||||
/goo\.gl/[a-zA-Z0-9]+
|
||||
# Google Chrome Store
|
||||
\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|)
|
||||
# Google Books
|
||||
\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]*
|
||||
# Google Fonts
|
||||
\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]*
|
||||
# Google Forms
|
||||
\bforms\.gle/\w+
|
||||
# Google Scholar
|
||||
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
|
||||
# Google Colab Research Drive
|
||||
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
|
||||
|
||||
# GitHub SHAs (api)
|
||||
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
|
||||
# GitHub SHAs (markdown)
|
||||
(?:\[`?[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 wiki
|
||||
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
|
||||
# githubusercontent
|
||||
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
|
||||
# githubassets
|
||||
\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+)
|
||||
# gist github
|
||||
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
|
||||
# git.io
|
||||
\bgit\.io/[0-9a-zA-Z]+
|
||||
# GitHub JSON
|
||||
"node_id": "[-a-zA-Z=;:/0-9+]*"
|
||||
# Contributor
|
||||
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
|
||||
# GHSA
|
||||
GHSA(?:-[0-9a-z]{4}){3}
|
||||
|
||||
# GitLab commit
|
||||
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
|
||||
# GitLab merge requests
|
||||
\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b
|
||||
# GitLab uploads
|
||||
\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]*
|
||||
# GitLab commits
|
||||
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
|
||||
|
||||
# binanace
|
||||
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]+
|
||||
# bitbucket repositories commits
|
||||
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
|
||||
# bitbucket commits
|
||||
\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
|
||||
|
||||
# bit.ly
|
||||
\bbit\.ly/\w+
|
||||
|
||||
# bitrise
|
||||
\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]*
|
||||
|
||||
# bootstrapcdn.com
|
||||
\bbootstrapcdn\.com/[-./\w]+
|
||||
|
||||
# cdn.cloudflare.com
|
||||
\bcdnjs\.cloudflare\.com/[./\w]+
|
||||
|
||||
# circleci
|
||||
\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+
|
||||
|
||||
# gitter
|
||||
\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+
|
||||
|
||||
# gravatar
|
||||
\bgravatar\.com/avatar/[0-9a-f]+
|
||||
|
||||
# ibm
|
||||
[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]*
|
||||
|
||||
# imgur
|
||||
\bimgur\.com/[^.]+
|
||||
|
||||
# Internet Archive
|
||||
\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*)
|
||||
|
||||
# discord
|
||||
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
|
||||
|
||||
# Disqus
|
||||
\bdisqus\.com/[-\w/%.()!?&=_]*
|
||||
|
||||
# medium link
|
||||
\blink\.medium\.com/[a-zA-Z0-9]+
|
||||
# medium
|
||||
\bmedium\.com/\@?[^/\s"]+/[-\w]+
|
||||
|
||||
# microsoft
|
||||
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
|
||||
# powerbi
|
||||
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
|
||||
# vs devops
|
||||
\bvisualstudio.com(?::443|)/[-\w/?=%&.]*
|
||||
# microsoft store
|
||||
\bmicrosoft\.com/store/apps/\w+
|
||||
|
||||
# mvnrepository.com
|
||||
\bmvnrepository\.com/[-0-9a-z./]+
|
||||
|
||||
# now.sh
|
||||
/[0-9a-z-.]+\.now\.sh\b
|
||||
|
||||
# oracle
|
||||
\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]*
|
||||
|
||||
# chromatic.com
|
||||
/\S+.chromatic.com\S*[")]
|
||||
|
||||
# codacy
|
||||
\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+
|
||||
|
||||
# compai
|
||||
\bcompai\.pub/v1/png/[0-9a-f]+
|
||||
|
||||
# mailgun api
|
||||
\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]*
|
||||
# mailgun
|
||||
\b[0-9a-z]+.mailgun.org
|
||||
|
||||
# /message-id/
|
||||
/message-id/[-\w@./%]+
|
||||
|
||||
# Reddit
|
||||
\breddit\.com/r/[/\w_]*
|
||||
|
||||
# requestb.in
|
||||
\brequestb\.in/[0-9a-z]+
|
||||
|
||||
# sched
|
||||
\b[a-z0-9]+\.sched\.com\b
|
||||
|
||||
# Slack url
|
||||
slack://[a-zA-Z0-9?&=]+
|
||||
# Slack
|
||||
\bslack\.com/[-0-9a-zA-Z/_~?&=.]*
|
||||
# Slack edge
|
||||
\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+
|
||||
# Slack images
|
||||
\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+
|
||||
|
||||
# shields.io
|
||||
\bshields\.io/[-\w/%?=&.:+;,]*
|
||||
|
||||
# stackexchange -- https://stackexchange.com/feeds/sites
|
||||
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
|
||||
|
||||
# Sentry
|
||||
[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b
|
||||
|
||||
# Twitter markdown
|
||||
\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\)
|
||||
# Twitter hashtag
|
||||
\btwitter\.com/hashtag/[\w?_=&]*
|
||||
# Twitter status
|
||||
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
|
||||
# Twitter profile images
|
||||
\btwimg\.com/profile_images/[_\w./]*
|
||||
# Twitter media
|
||||
\btwimg\.com/media/[-_\w./?=]*
|
||||
# Twitter link shortened
|
||||
\bt\.co/\w+
|
||||
|
||||
# facebook
|
||||
\bfburl\.com/[0-9a-z_]+
|
||||
# facebook CDN
|
||||
\bfbcdn\.net/[\w/.,]*
|
||||
# facebook watch
|
||||
\bfb\.watch/[0-9A-Za-z]+
|
||||
|
||||
# dropbox
|
||||
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
|
||||
|
||||
# ipfs protocol
|
||||
ipfs://[0-9a-z]*
|
||||
# ipfs url
|
||||
/ipfs/[0-9a-z]*
|
||||
|
||||
# w3
|
||||
\bw3\.org/[-0-9a-zA-Z/#.]+
|
||||
|
||||
# loom
|
||||
\bloom\.com/embed/[0-9a-f]+
|
||||
|
||||
# regex101
|
||||
\bregex101\.com/r/[^/\s"]+/\d+
|
||||
|
||||
# figma
|
||||
\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+
|
||||
|
||||
# freecodecamp.org
|
||||
\bfreecodecamp\.org/[-\w/.]+
|
||||
|
||||
# image.tmdb.org
|
||||
\bimage\.tmdb\.org/[/\w.]+
|
||||
|
||||
# mermaid
|
||||
\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+
|
||||
|
||||
# Wikipedia
|
||||
\ben\.wikipedia\.org/wiki/[-\w%.#]+
|
||||
|
||||
# gitweb
|
||||
[^"\s]+/gitweb/\S+;h=[0-9a-f]+
|
||||
|
||||
# HyperKitty lists
|
||||
/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/
|
||||
|
||||
# lists
|
||||
/thread\.html/[^"\s]+
|
||||
|
||||
# list-management
|
||||
\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+
|
||||
|
||||
# kubectl.kubernetes.io/last-applied-configuration
|
||||
"kubectl.kubernetes.io/last-applied-configuration": ".*"
|
||||
|
||||
# pgp
|
||||
\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]*
|
||||
|
||||
# Spotify
|
||||
\bopen\.spotify\.com/embed/playlist/\w+
|
||||
|
||||
# Mastodon
|
||||
\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]*
|
||||
|
||||
# scastie
|
||||
\bscastie\.scala-lang\.org/[^/]+/\w+
|
||||
|
||||
# images.unsplash.com
|
||||
\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+
|
||||
|
||||
# pastebin
|
||||
\bpastebin\.com/[\w/]+
|
||||
|
||||
# heroku
|
||||
\b\w+\.heroku\.com/source/archive/\w+
|
||||
|
||||
# quip
|
||||
\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)?
|
||||
|
||||
# badgen.net
|
||||
\bbadgen\.net/badge/[^")\]'\s]+
|
||||
|
||||
# statuspage.io
|
||||
\w+\.statuspage\.io\b
|
||||
|
||||
# media.giphy.com
|
||||
\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+
|
||||
|
||||
# tinyurl
|
||||
\btinyurl\.com/\w+
|
||||
|
||||
# getopts
|
||||
\bgetopts\s+(?:"[^"]+"|'[^']+')
|
||||
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
|
||||
# URL escaped characters
|
||||
\%[0-9A-F][A-F]
|
||||
# IPv6
|
||||
\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}
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
# hex in url queries
|
||||
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
|
||||
# ssh
|
||||
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
|
||||
|
||||
# PGP
|
||||
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
|
||||
# GPG keys
|
||||
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
|
||||
# Well known gpg keys
|
||||
.well-known/openpgpkey/[\w./]+
|
||||
|
||||
# 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
|
||||
# integrity
|
||||
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
|
||||
|
||||
# https://www.gnu.org/software/groff/manual/groff.html
|
||||
# man troff content
|
||||
\\f[BCIPR]
|
||||
# '
|
||||
\\\(aq
|
||||
|
||||
# .desktop mime types
|
||||
^MimeTypes?=.*$
|
||||
# .desktop localized entries
|
||||
^[A-Z][a-z]+\[[a-z]+\]=.*$
|
||||
# Localized .desktop content
|
||||
Name\[[^\]]+\]=.*
|
||||
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
|
||||
# crypt
|
||||
"\$2[ayb]\$.{56}"
|
||||
|
||||
# scrypt / argon
|
||||
\$(?:scrypt|argon\d+[di]*)\$\S+
|
||||
|
||||
# Input to GitHub JSON
|
||||
content: "[-a-zA-Z=;:/0-9+]*="
|
||||
|
||||
# Python stringprefix / binaryprefix
|
||||
# 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,})
|
||||
|
||||
# Regular expressions for (P|p)assword
|
||||
\([A-Z]\|[a-z]\)[a-z]+
|
||||
|
||||
# JavaScript regular expressions
|
||||
# javascript test regex
|
||||
/.*/[gim]*\.test\(
|
||||
# javascript match regex
|
||||
\.match\(/[^/\s"]*/[gim]*\s*
|
||||
# javascript match regex
|
||||
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
|
||||
# javascript regex
|
||||
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
|
||||
# javascript replace regex
|
||||
\.replace\(/[^/\s"]*/[gim]*\s*,
|
||||
|
||||
# Go regular expressions
|
||||
regexp?\.MustCompile\(`[^`]*`\)
|
||||
|
||||
# sed regular expressions
|
||||
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
|
||||
|
||||
# go install
|
||||
go install(?:\s+[a-z]+\.[-@\w/.]+)+
|
||||
|
||||
# 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+
|
||||
|
||||
# kubectl - pods in CrashLoopBackOff
|
||||
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
|
||||
|
||||
# kubernetes object suffix
|
||||
-[0-9a-f]{10}-\w{5}\s
|
||||
|
||||
# posthog secrets
|
||||
posthog\.init\((['"])phc_[^"',]+\g{-1},
|
||||
|
||||
# xcode
|
||||
|
||||
# xcodeproject scenes
|
||||
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
|
||||
|
||||
# xcode api botches
|
||||
customObjectInstantitationMethod
|
||||
|
||||
# font awesome classes
|
||||
\.fa-[-a-z0-9]+
|
||||
|
||||
# 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|[,.])*
|
||||
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-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]+)
|
||||
|
||||
# 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])
|
||||
# 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 (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
|
||||
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
|
||||
# tar arguments
|
||||
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\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
|
||||
# macOS temp folders
|
||||
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/
|
||||
45
.github/actions/spelling/excludes.txt
vendored
45
.github/actions/spelling/excludes.txt
vendored
@@ -1,28 +1,39 @@
|
||||
# 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$
|
||||
(?:^|/)package(?:-lock|)\.json$
|
||||
(?:^|/)sources(?:|\.dep)$
|
||||
SUMS$
|
||||
(?:^|/)vendor/
|
||||
\.a$
|
||||
\.ai$
|
||||
\.avi$
|
||||
\.bmp$
|
||||
\.bz2$
|
||||
\.cer$
|
||||
\.class$
|
||||
\.crl$
|
||||
\.crt$
|
||||
\.csr$
|
||||
\.dll$
|
||||
\.docx?$
|
||||
\.drawio$
|
||||
\.DS_Store$
|
||||
\.eot$
|
||||
\.eps$
|
||||
\.exe$
|
||||
\.gif$
|
||||
\.gitattributes$
|
||||
\.graffle$
|
||||
\.gz$
|
||||
\.icns$
|
||||
\.ico$
|
||||
\.jar$
|
||||
\.jks$
|
||||
\.jpeg$
|
||||
\.jpg$
|
||||
\.key$
|
||||
@@ -30,28 +41,52 @@ SUMS$
|
||||
\.lock$
|
||||
\.map$
|
||||
\.min\..
|
||||
\.mod$
|
||||
\.mp3$
|
||||
\.mp4$
|
||||
\.o$
|
||||
\.ocf$
|
||||
\.otf$
|
||||
\.pbxproj$
|
||||
\.pdf$
|
||||
\.pem$
|
||||
\.png$
|
||||
\.psd$
|
||||
\.pyc$
|
||||
\.runsettings$
|
||||
\.s$
|
||||
\.sig$
|
||||
\.so$
|
||||
\.svg$
|
||||
\.svgz$
|
||||
\.svgz?$
|
||||
\.tar$
|
||||
\.tgz$
|
||||
\.tiff?$
|
||||
\.ttf$
|
||||
\.vsdx$
|
||||
\.wav$
|
||||
\.webm$
|
||||
\.webp$
|
||||
\.woff
|
||||
\.woff2?$
|
||||
\.xcf$
|
||||
\.xls
|
||||
\.xlsx?$
|
||||
\.xpm$
|
||||
\.yml$
|
||||
\.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$
|
||||
^\Qsrc/host/ft_host/chafa.txt\E$
|
||||
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
|
||||
^\XamlStyler.json$
|
||||
^build/config/
|
||||
^consolegit2gitfilters\.json$
|
||||
^dep/
|
||||
@@ -78,7 +113,5 @@ SUMS$
|
||||
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
|
||||
^src/types/ut_types/UtilsTests.cpp$
|
||||
^tools/ReleaseEngineering/ServicingPipeline.ps1$
|
||||
^\.github/actions/spelling/
|
||||
^\.github/fabricbot.json$
|
||||
^\.gitignore$
|
||||
^\XamlStyler.json$
|
||||
ignore$
|
||||
SUMS$
|
||||
|
||||
8
.github/actions/spelling/expect/alphabet.txt
vendored
8
.github/actions/spelling/expect/alphabet.txt
vendored
@@ -5,26 +5,19 @@ AAAAAABBBBBBCCC
|
||||
AAAAABBBBBBCCC
|
||||
abcd
|
||||
abcd
|
||||
abcde
|
||||
abcdef
|
||||
ABCDEFG
|
||||
ABCDEFGH
|
||||
ABCDEFGHIJ
|
||||
abcdefghijk
|
||||
ABCDEFGHIJKLMNO
|
||||
abcdefghijklmnop
|
||||
ABCDEFGHIJKLMNOPQRST
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
ABCG
|
||||
ABE
|
||||
abf
|
||||
BBBBB
|
||||
BBBBBBBB
|
||||
BBBBBBBBBBBBBBDDDD
|
||||
BBBBBCCC
|
||||
BBBBCCCCC
|
||||
BBGGRR
|
||||
CCE
|
||||
EFG
|
||||
EFGh
|
||||
QQQQQQQQQQABCDEFGHIJ
|
||||
@@ -33,7 +26,6 @@ QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
|
||||
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
|
||||
qrstuvwxyz
|
||||
qwerty
|
||||
QWERTYUIOP
|
||||
qwertyuiopasdfg
|
||||
YYYYYYYDDDDDDDDDDD
|
||||
ZAAZZ
|
||||
|
||||
883
.github/actions/spelling/expect/expect.txt
vendored
883
.github/actions/spelling/expect/expect.txt
vendored
File diff suppressed because it is too large
Load Diff
23
.github/actions/spelling/expect/web.txt
vendored
23
.github/actions/spelling/expect/web.txt
vendored
@@ -1,29 +1,6 @@
|
||||
http
|
||||
www
|
||||
easyrgb
|
||||
php
|
||||
ecma
|
||||
rapidtables
|
||||
WCAG
|
||||
freedesktop
|
||||
ycombinator
|
||||
robertelder
|
||||
kovidgoyal
|
||||
leonerd
|
||||
fixterms
|
||||
winui
|
||||
appshellintegration
|
||||
mdtauk
|
||||
cppreference
|
||||
gfycat
|
||||
Guake
|
||||
azurewebsites
|
||||
askubuntu
|
||||
dostips
|
||||
viewtopic
|
||||
rosettacode
|
||||
Rexx
|
||||
tldp
|
||||
HOWTO
|
||||
uwspace
|
||||
uwaterloo
|
||||
|
||||
62
.github/actions/spelling/line_forbidden.patterns
vendored
Normal file
62
.github/actions/spelling/line_forbidden.patterns
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
|
||||
# \bm_data\b
|
||||
|
||||
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
|
||||
# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want
|
||||
# to use this:
|
||||
#\bfit\(
|
||||
|
||||
# s.b. GitHub
|
||||
\bGithub\b
|
||||
|
||||
# s.b. GitLab
|
||||
\bGitlab\b
|
||||
|
||||
# s.b. JavaScript
|
||||
\bJavascript\b
|
||||
|
||||
# s.b. Microsoft
|
||||
\bMicroSoft\b
|
||||
|
||||
# s.b. another
|
||||
\ban[- ]other\b
|
||||
|
||||
# s.b. greater than
|
||||
\bgreater then\b
|
||||
|
||||
# s.b. into
|
||||
#\sin to\s
|
||||
|
||||
# s.b. opt-in
|
||||
\sopt in\s
|
||||
|
||||
# s.b. less than
|
||||
\bless then\b
|
||||
|
||||
# s.b. otherwise
|
||||
\bother[- ]wise\b
|
||||
|
||||
# s.b. nonexistent
|
||||
\bnon existing\b
|
||||
\b[Nn]o[nt][- ]existent\b
|
||||
|
||||
# s.b. preexisting
|
||||
[Pp]re[- ]existing
|
||||
|
||||
# s.b. preempt
|
||||
[Pp]re[- ]empt\b
|
||||
|
||||
# s.b. preemptively
|
||||
[Pp]re[- ]emptively
|
||||
|
||||
# s.b. reentrancy
|
||||
[Rr]e[- ]entrancy
|
||||
|
||||
# s.b. reentrant
|
||||
[Rr]e[- ]entrant
|
||||
|
||||
# s.b. workaround(s)
|
||||
#\bwork[- ]arounds?\b
|
||||
|
||||
# Reject duplicate words
|
||||
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s
|
||||
82
.github/actions/spelling/patterns/patterns.txt
vendored
82
.github/actions/spelling/patterns/patterns.txt
vendored
@@ -1,11 +1,6 @@
|
||||
https://(?:(?:[-a-zA-Z0-9?&=]*\.|)microsoft\.com)/[-a-zA-Z0-9?&=_#\/.]*
|
||||
https://aka\.ms/[-a-zA-Z0-9?&=\/_]*
|
||||
https://www\.itscj\.ipsj\.or\.jp/iso-ir/[-0-9]+\.pdf
|
||||
https://www\.vt100\.net/docs/[-a-zA-Z0-9#_\/.]*
|
||||
https://www.w3.org/[-a-zA-Z0-9?&=\/_#]*
|
||||
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
|
||||
https://(?:[a-z-]+\.|)github(?:usercontent|)\.com/[-a-zA-Z0-9?%&=_\/.+]*
|
||||
https://www.xfree86.org/[-a-zA-Z0-9?&=\/_#]*
|
||||
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
|
||||
|
||||
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
|
||||
@@ -28,3 +23,74 @@ vcvars\w*
|
||||
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)'
|
||||
|
||||
# Automatically suggested patterns
|
||||
# hit-count: 3831 file-count: 582
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[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](?=[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
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
|
||||
# hit-count: 10 file-count: 7
|
||||
# uuid:
|
||||
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
|
||||
|
||||
# hit-count: 4 file-count: 4
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
# hit-count: 4 file-count: 1
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
|
||||
# hit-count: 2 file-count: 1
|
||||
# latex
|
||||
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
|
||||
# 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
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# Commit message -- Signed-off-by and friends
|
||||
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$
|
||||
|
||||
# Autogenerated revert commit message
|
||||
^This reverts commit [0-9a-f]{40}\.$
|
||||
|
||||
# vtmode
|
||||
--vtmode\s+(\w+)\s+\g{-1}\s
|
||||
|
||||
# ignore long runs of a single character:
|
||||
\b([A-Za-z])\g{-1}{3,}\b
|
||||
|
||||
28
.github/actions/spelling/reject.txt
vendored
28
.github/actions/spelling/reject.txt
vendored
@@ -1,22 +1,12 @@
|
||||
^attache$
|
||||
^attacher$
|
||||
^attachers$
|
||||
^spae$
|
||||
^spaebook$
|
||||
^spaecraft$
|
||||
^spaed$
|
||||
^spaedom$
|
||||
^spaeing$
|
||||
^spaeings$
|
||||
^spae-man$
|
||||
^spaeman$
|
||||
^spaer$
|
||||
^Spaerobee$
|
||||
^spaes$
|
||||
^spaewife$
|
||||
^spaewoman$
|
||||
^spaework$
|
||||
^spaewright$
|
||||
^wether$
|
||||
^wethers$
|
||||
^wetherteg$
|
||||
benefitting
|
||||
occurences?
|
||||
^dependan.*
|
||||
^oer$
|
||||
Sorce
|
||||
^[Ss]pae.*
|
||||
^untill$
|
||||
^untilling$
|
||||
^wether.*
|
||||
|
||||
132
.github/workflows/spelling2.yml
vendored
132
.github/workflows/spelling2.yml
vendored
@@ -1,20 +1,134 @@
|
||||
# spelling.yml is blocked per https://github.com/check-spelling/check-spelling/security/advisories/GHSA-g86g-chm8-7r2p
|
||||
name: Spell checking
|
||||
|
||||
# Comment management is handled through a secondary job, for details see:
|
||||
# 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)
|
||||
# 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
|
||||
# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment)
|
||||
# it needs `pull-requests: write` in order to manipulate those comments.
|
||||
|
||||
# Updating pull request branches is managed via comment handling.
|
||||
# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list
|
||||
#
|
||||
# These elements work together to make it happen:
|
||||
#
|
||||
# `on.issue_comment`
|
||||
# This event listens to comments by users asking to update the metadata.
|
||||
#
|
||||
# `jobs.update`
|
||||
# This job runs in response to an issue_comment and will push a new commit
|
||||
# to update the spelling metadata.
|
||||
#
|
||||
# `with.experimental_apply_changes_via_bot`
|
||||
# Tells the action to support and generate messages that enable it
|
||||
# to make a commit to update the spelling metadata.
|
||||
#
|
||||
# `with.ssh_key`
|
||||
# In order to trigger workflows when the commit is made, you can provide a
|
||||
# secret (typically, a write-enabled github deploy key).
|
||||
#
|
||||
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
push:
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
types:
|
||||
- 'opened'
|
||||
- 'reopened'
|
||||
- 'synchronize'
|
||||
issue_comment:
|
||||
types:
|
||||
- 'created'
|
||||
|
||||
jobs:
|
||||
spelling:
|
||||
name: Spell checking
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
actions: read
|
||||
outputs:
|
||||
followup: ${{ steps.spelling.outputs.followup }}
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- name: checkout-merge
|
||||
if: "contains(github.event_name, 'pull_request')"
|
||||
uses: actions/checkout@v2
|
||||
- name: check-spelling
|
||||
id: spelling
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
with:
|
||||
ref: refs/pull/${{github.event.pull_request.number}}/merge
|
||||
- name: checkout
|
||||
if: "!contains(github.event_name, 'pull_request')"
|
||||
uses: actions/checkout@v2
|
||||
- uses: check-spelling/check-spelling@v0.0.19
|
||||
suppress_push_for_open_pull_request: 1
|
||||
checkout: true
|
||||
check_file_names: 1
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
post_comment: 0
|
||||
use_magic_file: 1
|
||||
extra_dictionary_limit: 10
|
||||
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:cpp/src/stdlib-cpp.txt
|
||||
cspell:fullstack/fullstack.txt
|
||||
cspell:filetypes/filetypes.txt
|
||||
cspell:html/html.txt
|
||||
cspell:cpp/src/compiler-msvc.txt
|
||||
cspell:python/src/common/extra.txt
|
||||
cspell:powershell/powershell.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:cpp/src/stdlib-cmath.txt
|
||||
check_extra_dictionaries: ''
|
||||
|
||||
comment-push:
|
||||
name: Report (Push)
|
||||
# If your workflow isn't running on push, you can remove this job
|
||||
runs-on: ubuntu-latest
|
||||
needs: spelling
|
||||
permissions:
|
||||
contents: write
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
task: ${{ needs.spelling.outputs.followup }}
|
||||
|
||||
comment-pr:
|
||||
name: Report (PR)
|
||||
# If you workflow isn't running on pull_request*, you can remove this job
|
||||
runs-on: ubuntu-latest
|
||||
needs: spelling
|
||||
permissions:
|
||||
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
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
task: ${{ needs.spelling.outputs.followup }}
|
||||
|
||||
@@ -11,9 +11,9 @@ Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "CascadiaPackage", "src\casc
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.EXE", "src\host\exe\Host.EXE.vcxproj", "{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
{5D23E8E1-3C64-4CC1-A8F7-6861677F7239} = {5D23E8E1-3C64-4CC1-A8F7-6861677F7239}
|
||||
{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropertiesLibrary", "src\propslib\propslib.vcxproj", "{345FD5A4-B32B-4F29-BD1C-B033BD2C35CC}"
|
||||
@@ -64,9 +64,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererGdi", "src\renderer
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host", "src\host\lib\hostlib.vcxproj", "{06EC74CB-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
|
||||
{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.unittest", "src\host\ut_lib\host.unittest.vcxproj", "{06EC74CB-9A12-429C-B551-8562EC954747}"
|
||||
@@ -77,8 +77,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.unittest", "src\host\u
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Unit", "src\host\ut_host\Host.UnitTests.vcxproj", "{531C23E7-4B76-4C08-8AAD-04164CB628C9}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
{06EC74CB-9A12-429C-B551-8562EC954747} = {06EC74CB-9A12-429C-B551-8562EC954747}
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextBuffer.Unit.Tests", "src\buffer\out\ut_textbuffer\TextBuffer.Unit.Tests.vcxproj", "{531C23E7-4B76-4C08-8BBD-04164CB628C9}"
|
||||
@@ -89,9 +89,9 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Feature", "src\host\ft_host\Host.FeatureTests.vcxproj", "{8CDB8850-7484-4EC7-B45B-181F85B2EE54}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
|
||||
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
|
||||
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalParser.UnitTests", "src\terminal\parser\ut_parser\Parser.UnitTests.vcxproj", "{12144E07-FE63-4D33-9231-748B8D8C3792}"
|
||||
@@ -114,8 +114,8 @@ EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Host.Tests.UIA", "src\host\ft_uia\Host.Tests.UIA.csproj", "{C17E1BF3-9D34-4779-9458-A8EF98CC5662}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{099193A0-1E43-4BBC-BA7F-7B351E1342DF} = {099193A0-1E43-4BBC-BA7F-7B351E1342DF}
|
||||
{C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB} = {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB} = {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VTApp", "src\tools\vtapp\VTApp.csproj", "{099193A0-1E43-4BBC-BA7F-7B351E1342DF}"
|
||||
@@ -172,12 +172,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalCore", "src\cascadi
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control.Lib", "src\cascadia\TerminalControl\TerminalControlLib.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{1CF55140-EF6A-4736-A403-957E4F7430BB} = {1CF55140-EF6A-4736-A403-957E4F7430BB}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF62} = {48D21369-3D7B-4431-9967-24E81292CF62}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63} = {48D21369-3D7B-4431-9967-24E81292CF63}
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {8222900C-8B6C-452A-91AC-BE95DB04B95F}
|
||||
{AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} = {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control", "src\cascadia\TerminalControl\dll\TerminalControl.vcxproj", "{CA5CAD1A-F542-4635-A069-7CAEFB930070}"
|
||||
@@ -187,21 +188,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj", "{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminalShellExt", "src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj", "{F2ED628A-DB22-446F-A081-4CC845B51A2B}"
|
||||
@@ -251,15 +252,15 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@@ -273,9 +274,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winconpty.DLL", "src\wincon
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHostApp", "src\cascadia\LocalTests_TerminalApp\TestHostApp\TestHostApp.vcxproj", "{A021EDFF-45C8-4DC2-BEF7-36E1B3B8CFE8}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {CA5CAD1A-9B68-456A-B13E-C8218070DC42}
|
||||
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BDB237B6-1D1D-400F-84CC-40A58FA59C8E}"
|
||||
@@ -330,8 +331,8 @@ 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
|
||||
{A22EC5F6-7851-4B88-AC52-47249D437A52} = {A22EC5F6-7851-4B88-AC52-47249D437A52}
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890} = {84848BFA-931D-42CE-9ADF-01EE54DE7890}
|
||||
{A22EC5F6-7851-4B88-AC52-47249D437A52} = {A22EC5F6-7851-4B88-AC52-47249D437A52}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}"
|
||||
@@ -356,9 +357,9 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_SettingsModel", "src\cascadia\LocalTests_SettingsModel\SettingsModel.LocalTests.vcxproj", "{CA5CAD1A-9B68-456A-B13E-C8218070DC42}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MonarchPeasantSample", "src\tools\MonarchPeasantSample\MonarchPeasantSample.vcxproj", "{21B7EA5E-1EF8-49B6-AC07-11714AF0E37D}"
|
||||
@@ -377,8 +378,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Remoting
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_Remoting", "src\cascadia\UnitTests_Remoting\Remoting.UnitTests.vcxproj", "{68A10CD3-AA64-465B-AF5F-ED4E9700543C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{43CE4CE5-0010-4B99-9569-672670D26E26} = {43CE4CE5-0010-4B99-9569-672670D26E26}
|
||||
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}
|
||||
{43CE4CE5-0010-4B99-9569-672670D26E26} = {43CE4CE5-0010-4B99-9569-672670D26E26}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wpf", "wpf", "{4DAF0299-495E-4CD1-A982-9BAC16A45932}"
|
||||
@@ -644,7 +645,8 @@ Global
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -662,7 +664,8 @@ Global
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x64.Build.0 = Release|x64
|
||||
@@ -2309,7 +2312,8 @@ Global
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -2326,7 +2330,8 @@ Global
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|x64.ActiveCfg = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|x64.Build.0 = Release|x64
|
||||
@@ -3357,7 +3362,8 @@ Global
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -3377,7 +3383,8 @@ Global
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.ActiveCfg = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.Build.0 = Release|x64
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"collection": "microsoft",
|
||||
"project": "OS",
|
||||
"repo": "os.2020",
|
||||
"name": "official/rs_wdx_dxp_windev",
|
||||
"name": "official/rs_we_adept_e4d2",
|
||||
"workitem": "38106206",
|
||||
"CheckinFiles": [
|
||||
{
|
||||
@@ -21,4 +21,4 @@
|
||||
"sendOnErrorOnly": "False"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,7 @@
|
||||
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<!-- This cannot be included in another project that depends on XAML (as it would be a duplicate package ID) -->
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.0" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.PdbStr" version="20220617.1556.0" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.SrcTool" version="20220617.1556.0" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
|
||||
<PGOBranch>main</PGOBranch>
|
||||
<PGOBranch>release-1.15</PGOBranch>
|
||||
|
||||
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
|
||||
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>
|
||||
|
||||
@@ -134,8 +134,6 @@ jobs:
|
||||
|
||||
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
|
||||
- template: .\templates\restore-nuget-steps.yml
|
||||
# Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
|
||||
- template: .\templates\install-winsdk-steps.yml
|
||||
- task: UniversalPackages@0
|
||||
displayName: Download terminal-internal Universal Package
|
||||
inputs:
|
||||
@@ -241,6 +239,7 @@ jobs:
|
||||
filePath: build\scripts\Index-Pdbs.ps1
|
||||
arguments: -SearchDir '$(Build.SourcesDirectory)' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
|
||||
errorActionPreference: silentlyContinue
|
||||
pwsh: true
|
||||
- task: PowerShell@2
|
||||
displayName: Run Unit Tests
|
||||
condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'x86')))
|
||||
@@ -336,6 +335,13 @@ jobs:
|
||||
${{ windowsVersion }}:
|
||||
TerminalTargetWindowsVersion: ${{ windowsVersion }}
|
||||
displayName: Create and sign AppX/MSIX bundles
|
||||
variables:
|
||||
${{ if eq(parameters.branding, 'Release') }}:
|
||||
BundleStemName: Microsoft.WindowsTerminal
|
||||
${{ elseif eq(parameters.branding, 'Preview') }}:
|
||||
BundleStemName: Microsoft.WindowsTerminalPreview
|
||||
${{ else }}:
|
||||
BundleStemName: WindowsTerminalDev
|
||||
dependsOn: Build
|
||||
steps:
|
||||
- checkout: self
|
||||
@@ -360,14 +366,15 @@ jobs:
|
||||
$Components = "$(XES_APPXMANIFESTVERSION)" -Split "\."
|
||||
$Components[0] = ([int]$Components[0] + $VersionEpoch)
|
||||
$BundleVersion = $Components -Join "."
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
New-Item -Type Directory "$(System.ArtifactsDirectory)\bundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
displayName: Create WindowsTerminal*.msixbundle
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: Submit *.msixbundle to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
FolderPath: $(System.ArtifactsDirectory)
|
||||
Pattern: Microsoft.WindowsTerminal*.msixbundle
|
||||
FolderPath: $(System.ArtifactsDirectory)\bundle
|
||||
Pattern: $(BundleStemName)*.msixbundle
|
||||
UseMinimatch: true
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: >-
|
||||
@@ -400,7 +407,7 @@ jobs:
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: appxbundle-signed'
|
||||
inputs:
|
||||
PathtoPublish: $(System.ArtifactsDirectory)
|
||||
PathtoPublish: $(System.ArtifactsDirectory)\bundle
|
||||
ArtifactName: appxbundle-signed-$(TerminalTargetWindowsVersion)
|
||||
|
||||
- ${{ if eq(parameters.buildConPTY, true) }}:
|
||||
@@ -612,6 +619,8 @@ jobs:
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
|
||||
- template: .\templates\restore-nuget-steps.yml
|
||||
|
||||
# Download the appx-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- ${{ each windowsVersion in parameters.buildWindowsVersions }}:
|
||||
@@ -634,13 +643,12 @@ jobs:
|
||||
}
|
||||
displayName: Extract symbols for public consumption
|
||||
|
||||
# Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
|
||||
- template: .\templates\install-winsdk-steps.yml
|
||||
- task: PowerShell@2
|
||||
displayName: Source Index PDBs (the public ones)
|
||||
inputs:
|
||||
filePath: build\scripts\Index-Pdbs.ps1
|
||||
arguments: -SearchDir '$(Build.SourcesDirectory)/appxsym-temp' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
|
||||
pwsh: true
|
||||
|
||||
# Publish the app symbols to the public MSDL symbol server
|
||||
# accessible via https://msdl.microsoft.com/download/symbols
|
||||
@@ -706,6 +714,7 @@ jobs:
|
||||
description: VPack for the Windows Terminal Application
|
||||
pushPkgName: WindowsTerminal.app
|
||||
owner: conhost
|
||||
githubToken: $(GitHubTokenForVpackProvenance)
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Copy VPack Manifest to Drop'
|
||||
inputs:
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
parameters:
|
||||
sdkVersion: 18362
|
||||
steps:
|
||||
- task: powershell@2
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Install-WindowsSdkISO.ps1
|
||||
arguments: ${{ parameters.sdkVersion }}
|
||||
displayName: 'Install Windows SDK (${{ parameters.sdkVersion }})'
|
||||
@@ -8,10 +8,11 @@ Param(
|
||||
[switch]$recursive
|
||||
)
|
||||
|
||||
$debuggerPath = (Get-ItemProperty -path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" -name WindowsDebuggersRoot10).WindowsDebuggersRoot10
|
||||
$srcsrvPath = Join-Path $debuggerPath "x64\srcsrv"
|
||||
$srctoolExe = Join-Path $srcsrvPath "srctool.exe"
|
||||
$pdbstrExe = Join-Path $srcsrvPath "pdbstr.exe"
|
||||
$pdbStrPackage = ([xml](Get-Content "$SourceRoot\build\packages.config")).packages.package | Where-Object id -like "*PdbStr*"
|
||||
# This assumes that we rev PdbStr and SrcTool at the same time.
|
||||
$debugPackageVersions = $pdbStrPackage.version
|
||||
$srctoolExe = Join-Path $SourceRoot "packages" "Microsoft.Debugging.Tools.SrcTool.$debugPackageVersions" "content" "amd64" "srctool.exe"
|
||||
$pdbstrExe = Join-Path $SourceRoot "packages" "Microsoft.Debugging.Tools.PdbStr.$debugPackageVersions" "content" "amd64" "pdbstr.exe"
|
||||
|
||||
$fileTable = @{}
|
||||
foreach ($gitFile in & git ls-files)
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param([Parameter(Mandatory=$true, Position=0)]
|
||||
[string]$buildNumber)
|
||||
|
||||
# Ensure the error action preference is set to the default for PowerShell3, 'Stop'
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Constants
|
||||
$WindowsSDKOptions = @("OptionId.UWPCpp", "OptionId.DesktopCPPx64", "OptionId.DesktopCPPx86", "OptionId.DesktopCPPARM64", "OptionId.DesktopCPPARM", "OptionId.WindowsDesktopDebuggers")
|
||||
$WindowsSDKRegPath = "HKLM:\Software\WOW6432Node\Microsoft\Windows Kits\Installed Roots"
|
||||
$WindowsSDKRegRootKey = "KitsRoot10"
|
||||
$WindowsSDKVersion = "10.0.$buildNumber.0"
|
||||
$WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options"
|
||||
$StrongNameRegPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification"
|
||||
$PublicKeyTokens = @("31bf3856ad364e35")
|
||||
|
||||
if ($buildNumber -notmatch "^\d{5,}$")
|
||||
{
|
||||
Write-Host "ERROR: '$buildNumber' doesn't look like a windows build number"
|
||||
Write-Host
|
||||
Exit 1
|
||||
}
|
||||
|
||||
function Download-File
|
||||
{
|
||||
param ([string] $outDir,
|
||||
[string] $downloadUrl,
|
||||
[string] $downloadName)
|
||||
|
||||
$downloadPath = Join-Path $outDir "$downloadName.download"
|
||||
$downloadDest = Join-Path $outDir $downloadName
|
||||
$downloadDestTemp = Join-Path $outDir "$downloadName.tmp"
|
||||
|
||||
Write-Host -NoNewline "Downloading $downloadName..."
|
||||
|
||||
$retries = 10
|
||||
$downloaded = $false
|
||||
while (-not $downloaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
$webclient = new-object System.Net.WebClient
|
||||
$webclient.DownloadFile($downloadUrl, $downloadPath)
|
||||
$downloaded = $true
|
||||
}
|
||||
catch [System.Net.WebException]
|
||||
{
|
||||
Write-Host
|
||||
Write-Warning "Failed to fetch updated file from $downloadUrl : $($error[0])"
|
||||
if (!(Test-Path $downloadDest))
|
||||
{
|
||||
if ($retries -gt 0)
|
||||
{
|
||||
Write-Host "$retries retries left, trying download again"
|
||||
$retries--
|
||||
start-sleep -Seconds 10
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "$downloadName was not found at $downloadDest"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning "$downloadName may be out of date"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unblock-File $downloadPath
|
||||
|
||||
$downloadDestTemp = $downloadPath;
|
||||
|
||||
# Delete and rename to final dest
|
||||
Write-Host "testing $downloadDest"
|
||||
if (Test-Path $downloadDest)
|
||||
{
|
||||
Write-Host "Deleting: $downloadDest"
|
||||
Remove-Item $downloadDest -Force
|
||||
}
|
||||
|
||||
Move-Item -Force $downloadDestTemp $downloadDest
|
||||
Write-Host "Done"
|
||||
|
||||
return $downloadDest
|
||||
}
|
||||
|
||||
function Get-ISODriveLetter
|
||||
{
|
||||
param ([string] $isoPath)
|
||||
|
||||
$diskImage = Get-DiskImage -ImagePath $isoPath
|
||||
if ($diskImage)
|
||||
{
|
||||
$volume = Get-Volume -DiskImage $diskImage
|
||||
|
||||
if ($volume)
|
||||
{
|
||||
$driveLetter = $volume.DriveLetter
|
||||
if ($driveLetter)
|
||||
{
|
||||
$driveLetter += ":"
|
||||
return $driveLetter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Mount-ISO
|
||||
{
|
||||
param ([string] $isoPath)
|
||||
|
||||
# Check if image is already mounted
|
||||
$isoDrive = Get-ISODriveLetter $isoPath
|
||||
|
||||
if (!$isoDrive)
|
||||
{
|
||||
Mount-DiskImage -ImagePath $isoPath -StorageType ISO | Out-Null
|
||||
}
|
||||
|
||||
$isoDrive = Get-ISODriveLetter $isoPath
|
||||
Write-Verbose "$isoPath mounted to ${isoDrive}:"
|
||||
}
|
||||
|
||||
function Dismount-ISO
|
||||
{
|
||||
param ([string] $isoPath)
|
||||
|
||||
$isoDrive = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter
|
||||
|
||||
if ($isoDrive)
|
||||
{
|
||||
Write-Verbose "$isoPath dismounted"
|
||||
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Disable-StrongName
|
||||
{
|
||||
param ([string] $publicKeyToken = "*")
|
||||
|
||||
reg ADD "HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
|
||||
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64")
|
||||
{
|
||||
reg ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Admin
|
||||
{
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal $identity
|
||||
$principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
function Test-RegistryPathAndValue
|
||||
{
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $path,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $value)
|
||||
|
||||
try
|
||||
{
|
||||
if (Test-Path $path)
|
||||
{
|
||||
Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null
|
||||
return $true
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Test-InstallWindowsSDK
|
||||
{
|
||||
$retval = $true
|
||||
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey)
|
||||
{
|
||||
# A Windows SDK is installed
|
||||
# Is an SDK of our version installed with the options we need?
|
||||
$allRequiredSdkOptionsInstalled = $true
|
||||
foreach($sdkOption in $WindowsSDKOptions)
|
||||
{
|
||||
if (!(Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value $sdkOption))
|
||||
{
|
||||
$allRequiredSdkOptionsInstalled = $false
|
||||
}
|
||||
}
|
||||
|
||||
if($allRequiredSdkOptionsInstalled)
|
||||
{
|
||||
# It appears we have what we need. Double check the disk
|
||||
$sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey
|
||||
if ($sdkRoot)
|
||||
{
|
||||
if (Test-Path $sdkRoot)
|
||||
{
|
||||
$refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion"
|
||||
if (Test-Path $refPath)
|
||||
{
|
||||
$umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion"
|
||||
if (Test-Path $umdPath)
|
||||
{
|
||||
# Pretty sure we have what we need
|
||||
$retval = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $retval
|
||||
}
|
||||
|
||||
function Test-InstallStrongNameHijack
|
||||
{
|
||||
foreach($publicKeyToken in $PublicKeyTokens)
|
||||
{
|
||||
$key = "$StrongNameRegPath\*,$publicKeyToken"
|
||||
if (!(Test-Path $key))
|
||||
{
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Host -NoNewline "Checking for installed Windows SDK $WindowsSDKVersion..."
|
||||
$InstallWindowsSDK = Test-InstallWindowsSDK
|
||||
if ($InstallWindowsSDK)
|
||||
{
|
||||
Write-Host "Installation required"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "INSTALLED"
|
||||
}
|
||||
|
||||
$StrongNameHijack = Test-InstallStrongNameHijack
|
||||
Write-Host -NoNewline "Checking if StrongName bypass required..."
|
||||
|
||||
if ($StrongNameHijack)
|
||||
{
|
||||
Write-Host "REQUIRED"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Done"
|
||||
}
|
||||
|
||||
if ($StrongNameHijack -or $InstallWindowsSDK)
|
||||
{
|
||||
if (!(Test-Admin))
|
||||
{
|
||||
Write-Host
|
||||
throw "ERROR: Elevation required"
|
||||
}
|
||||
}
|
||||
|
||||
if ($InstallWindowsSDK)
|
||||
{
|
||||
# Static(ish) link for Windows SDK
|
||||
# Note: there is a delay from Windows SDK announcements to availability via the static link
|
||||
$uri = "https://software-download.microsoft.com/download/sg/Windows_InsiderPreview_SDK_en-us_$($buildNumber)_1.iso";
|
||||
|
||||
if ($env:TEMP -eq $null)
|
||||
{
|
||||
$env:TEMP = Join-Path $env:SystemDrive 'temp'
|
||||
}
|
||||
|
||||
$winsdkTempDir = Join-Path (Join-Path $env:TEMP ([System.IO.Path]::GetRandomFileName())) "WindowsSDK"
|
||||
|
||||
if (![System.IO.Directory]::Exists($winsdkTempDir))
|
||||
{
|
||||
[void][System.IO.Directory]::CreateDirectory($winsdkTempDir)
|
||||
}
|
||||
|
||||
$file = "winsdk_$buildNumber.iso"
|
||||
|
||||
Write-Verbose "Getting WinSDK from $uri"
|
||||
$downloadFile = Download-File $winsdkTempDir $uri $file
|
||||
Write-Verbose "File is at $downloadFile"
|
||||
$downloadFileItem = Get-Item $downloadFile
|
||||
|
||||
# Check to make sure the file is at least 10 MB.
|
||||
if ($downloadFileItem.Length -lt 10*1024*1024)
|
||||
{
|
||||
Write-Host
|
||||
Write-Host "ERROR: Downloaded file doesn't look large enough to be an ISO. The requested version may not be on microsoft.com yet."
|
||||
Write-Host
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# TODO Check if zip, exe, iso, etc.
|
||||
try
|
||||
{
|
||||
Write-Host -NoNewline "Mounting ISO $file..."
|
||||
Mount-ISO $downloadFile
|
||||
Write-Host "Done"
|
||||
|
||||
$isoDrive = Get-ISODriveLetter $downloadFile
|
||||
|
||||
if (Test-Path $isoDrive)
|
||||
{
|
||||
Write-Host -NoNewLine "Installing WinSDK..."
|
||||
|
||||
$setupPath = Join-Path "$isoDrive" "WinSDKSetup.exe"
|
||||
Start-Process -Wait $setupPath "/features $WindowsSDKOptions /q"
|
||||
Write-Host "Done"
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Could not find mounted ISO at ${isoDrive}"
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Write-Host -NoNewline "Dismounting ISO $file..."
|
||||
Dismount-ISO $downloadFile
|
||||
Write-Host "Done"
|
||||
}
|
||||
}
|
||||
|
||||
if ($StrongNameHijack)
|
||||
{
|
||||
Write-Host -NoNewline "Disabling StrongName for Windows SDK..."
|
||||
|
||||
foreach($key in $PublicKeyTokens)
|
||||
{
|
||||
Disable-StrongName $key
|
||||
}
|
||||
|
||||
Write-Host "Done"
|
||||
}
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
This version should be tracked in all project packages.config files for projects that depend on Xaml.
|
||||
-->
|
||||
<TerminalMUXVersion>2.7.2-prerelease.220406002</TerminalMUXVersion>
|
||||
<TerminalMUXVersion>2.7.3-prerelease.220816001</TerminalMUXVersion>
|
||||
<!--
|
||||
For the Windows 11-specific build, we're targeting the public version of Microsoft.UI.Xaml.
|
||||
This version emits a package dependency instead of embedding the dependency in our own package.
|
||||
|
||||
This version should be tracked in build/packages.config.
|
||||
-->
|
||||
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.1</TerminalMUXVersion>
|
||||
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.3</TerminalMUXVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{"Registrations":[
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/component-detection-manifest.json",
|
||||
"Registrations": [
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/CLIUtils/CLI11",
|
||||
"commitHash": "dd0d8e4fe729e5b1110232c7a5c9566dad884686"
|
||||
}
|
||||
}
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/CLIUtils/CLI11",
|
||||
"commitHash": "5cb3efabce007c3a0230e4cc2e27da491c646b6c"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
[Amalgamated](https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated)
|
||||
from source commit
|
||||
[6aba23f](https://github.com/open-source-parsers/jsoncpp/commit/6aba23f4a8628d599a9ef7fa4811c4ff6e4070e2),
|
||||
release 1.9.3.
|
||||
[5defb4e](https://github.com/open-source-parsers/jsoncpp/commit/5defb4ed1a4293b8e2bf641e16b156fb9de498cc),
|
||||
release 1.9.5.
|
||||
|
||||
> Generating amalgamated source and header JsonCpp is provided with a script to
|
||||
> generate a single header and a single source file to ease inclusion into an
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{"Registrations":[
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/component-detection-manifest.json",
|
||||
"Registrations": [
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/open-source-parsers/jsoncpp",
|
||||
"commitHash": "6aba23f4a8628d599a9ef7fa4811c4ff6e4070e2"
|
||||
}
|
||||
}
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/open-source-parsers/jsoncpp",
|
||||
"commitHash": "5defb4ed1a4293b8e2bf641e16b156fb9de498cc"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
@@ -94,10 +94,10 @@ license you like.
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.3"
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 3
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
@@ -162,11 +162,10 @@ public:
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
* The pointer argument is tagged as "volatile" to prevent the
|
||||
* compiler optimizing out this critical step.
|
||||
*/
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
@@ -6,28 +6,28 @@
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
@@ -93,10 +93,10 @@ license you like.
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.3"
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 3
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
@@ -161,11 +161,10 @@ public:
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
* The pointer argument is tagged as "volatile" to prevent the
|
||||
* compiler optimizing out this critical step.
|
||||
*/
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
@@ -575,7 +574,7 @@ public:
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4251 4275)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push, 8)
|
||||
@@ -788,10 +787,10 @@ private:
|
||||
CZString(ArrayIndex index);
|
||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
CZString(CZString&& other);
|
||||
CZString(CZString&& other) noexcept;
|
||||
~CZString();
|
||||
CZString& operator=(const CZString& other);
|
||||
CZString& operator=(CZString&& other);
|
||||
CZString& operator=(CZString&& other) noexcept;
|
||||
|
||||
bool operator<(CZString const& other) const;
|
||||
bool operator==(CZString const& other) const;
|
||||
@@ -867,14 +866,15 @@ public:
|
||||
Value(const StaticString& value);
|
||||
Value(const String& value);
|
||||
Value(bool value);
|
||||
Value(std::nullptr_t ptr) = delete;
|
||||
Value(const Value& other);
|
||||
Value(Value&& other);
|
||||
Value(Value&& other) noexcept;
|
||||
~Value();
|
||||
|
||||
/// \note Overwrite existing comments. To preserve comments, use
|
||||
/// #swapPayload().
|
||||
Value& operator=(const Value& other);
|
||||
Value& operator=(Value&& other);
|
||||
Value& operator=(Value&& other) noexcept;
|
||||
|
||||
/// Swap everything.
|
||||
void swap(Value& other);
|
||||
@@ -1159,9 +1159,9 @@ private:
|
||||
public:
|
||||
Comments() = default;
|
||||
Comments(const Comments& that);
|
||||
Comments(Comments&& that);
|
||||
Comments(Comments&& that) noexcept;
|
||||
Comments& operator=(const Comments& that);
|
||||
Comments& operator=(Comments&& that);
|
||||
Comments& operator=(Comments&& that) noexcept;
|
||||
bool has(CommentPlacement slot) const;
|
||||
String get(CommentPlacement slot) const;
|
||||
void set(CommentPlacement slot, String comment);
|
||||
@@ -1442,8 +1442,8 @@ public:
|
||||
* because the returned references/pointers can be used
|
||||
* to change state of the base class.
|
||||
*/
|
||||
reference operator*() { return deref(); }
|
||||
pointer operator->() { return &deref(); }
|
||||
reference operator*() const { return const_cast<reference>(deref()); }
|
||||
pointer operator->() const { return const_cast<pointer>(&deref()); }
|
||||
};
|
||||
|
||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||
@@ -1506,8 +1506,7 @@ namespace Json {
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
|
||||
class JSONCPP_DEPRECATED(
|
||||
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
|
||||
class JSON_API Reader {
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
@@ -1524,13 +1523,13 @@ public:
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
||||
Reader(const Features& features);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
@@ -1797,6 +1796,9 @@ public:
|
||||
* - `"allowSpecialFloats": false or true`
|
||||
* - If true, special float values (NaNs and infinities) are allowed and
|
||||
* their values are lossfree restorable.
|
||||
* - `"skipBom": false or true`
|
||||
* - If true, if the input starts with the Unicode byte order mark (BOM),
|
||||
* it is skipped.
|
||||
*
|
||||
* You can examine 'settings_` yourself to see the defaults. You can also
|
||||
* write and read them just like any JSON Value.
|
||||
@@ -2000,6 +2002,8 @@ public:
|
||||
* - Number of precision digits for formatting of real values.
|
||||
* - "precisionType": "significant"(default) or "decimal"
|
||||
* - Type of precision for formatting of real values.
|
||||
* - "emitUTF8": false or true
|
||||
* - If true, outputs raw UTF8 strings instead of escaping them.
|
||||
|
||||
* You can examine 'settings_` yourself
|
||||
* to see the defaults. You can also write and read them just like any
|
||||
@@ -2035,7 +2039,7 @@ public:
|
||||
/** \brief Abstract class for writers.
|
||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||
*/
|
||||
class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
|
||||
class JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
@@ -2055,7 +2059,7 @@ public:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
|
||||
class JSON_API FastWriter
|
||||
: public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
@@ -2115,7 +2119,7 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
class JSON_API
|
||||
StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
@@ -2184,7 +2188,7 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
class JSON_API
|
||||
StyledStreamWriter {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -6,28 +6,28 @@
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
@@ -202,14 +202,18 @@ template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
|
||||
* Return iterator that would be the new end of the range [begin,end), if we
|
||||
* were to delete zeros in the end of string, but not the last zero before '.'.
|
||||
*/
|
||||
template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
|
||||
template <typename Iter>
|
||||
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
|
||||
for (; begin != end; --end) {
|
||||
if (*(end - 1) != '0') {
|
||||
return end;
|
||||
}
|
||||
// Don't delete the last zero before the decimal point.
|
||||
if (begin != (end - 1) && *(end - 2) == '.') {
|
||||
return end;
|
||||
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
|
||||
if (precision) {
|
||||
return end;
|
||||
}
|
||||
return end - 2;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
@@ -338,8 +342,7 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
|
||||
|
||||
// Since String is reference-counted, this at least does not
|
||||
// create an extra copy.
|
||||
String doc;
|
||||
std::getline(is, doc, static_cast<char> EOF);
|
||||
String doc(std::istreambuf_iterator<char>(is), {});
|
||||
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
|
||||
}
|
||||
|
||||
@@ -1409,8 +1412,11 @@ bool OurReader::readToken(Token& token) {
|
||||
if (features_.allowSingleQuotes_) {
|
||||
token.type_ = tokenString;
|
||||
ok = readStringSingleQuote();
|
||||
break;
|
||||
} // else fall through
|
||||
} else {
|
||||
// If we don't allow single quotes, this is a failure case.
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
token.type_ = tokenComment;
|
||||
ok = readComment();
|
||||
@@ -2152,7 +2158,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const {
|
||||
if (valid_keys.count(key))
|
||||
continue;
|
||||
if (invalid)
|
||||
(*invalid)[std::move(key)] = *si;
|
||||
(*invalid)[key] = *si;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -2667,7 +2673,7 @@ Value::CZString::CZString(const CZString& other) {
|
||||
storage_.length_ = other.storage_.length_;
|
||||
}
|
||||
|
||||
Value::CZString::CZString(CZString&& other)
|
||||
Value::CZString::CZString(CZString&& other) noexcept
|
||||
: cstr_(other.cstr_), index_(other.index_) {
|
||||
other.cstr_ = nullptr;
|
||||
}
|
||||
@@ -2693,7 +2699,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) {
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
|
||||
cstr_ = other.cstr_;
|
||||
index_ = other.index_;
|
||||
other.cstr_ = nullptr;
|
||||
@@ -2841,7 +2847,7 @@ Value::Value(const Value& other) {
|
||||
dupMeta(other);
|
||||
}
|
||||
|
||||
Value::Value(Value&& other) {
|
||||
Value::Value(Value&& other) noexcept {
|
||||
initBasic(nullValue);
|
||||
swap(other);
|
||||
}
|
||||
@@ -2856,7 +2862,7 @@ Value& Value::operator=(const Value& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value& Value::operator=(Value&& other) {
|
||||
Value& Value::operator=(Value&& other) noexcept {
|
||||
other.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
@@ -3320,7 +3326,8 @@ void Value::resize(ArrayIndex newSize) {
|
||||
if (newSize == 0)
|
||||
clear();
|
||||
else if (newSize > oldSize)
|
||||
this->operator[](newSize - 1);
|
||||
for (ArrayIndex i = oldSize; i < newSize; ++i)
|
||||
(*this)[i];
|
||||
else {
|
||||
for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
||||
value_.map_->erase(index);
|
||||
@@ -3781,14 +3788,15 @@ bool Value::isObject() const { return type() == objectValue; }
|
||||
Value::Comments::Comments(const Comments& that)
|
||||
: ptr_{cloneUnique(that.ptr_)} {}
|
||||
|
||||
Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
|
||||
Value::Comments::Comments(Comments&& that) noexcept
|
||||
: ptr_{std::move(that.ptr_)} {}
|
||||
|
||||
Value::Comments& Value::Comments::operator=(const Comments& that) {
|
||||
ptr_ = cloneUnique(that.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::Comments& Value::Comments::operator=(Comments&& that) {
|
||||
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
|
||||
ptr_ = std::move(that.ptr_);
|
||||
return *this;
|
||||
}
|
||||
@@ -3804,13 +3812,11 @@ String Value::Comments::get(CommentPlacement slot) const {
|
||||
}
|
||||
|
||||
void Value::Comments::set(CommentPlacement slot, String comment) {
|
||||
if (!ptr_) {
|
||||
if (slot >= CommentPlacement::numberOfCommentPlacement)
|
||||
return;
|
||||
if (!ptr_)
|
||||
ptr_ = std::unique_ptr<Array>(new Array());
|
||||
}
|
||||
// check comments array boundry.
|
||||
if (slot < CommentPlacement::numberOfCommentPlacement) {
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
}
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
}
|
||||
|
||||
void Value::setComment(String comment, CommentPlacement placement) {
|
||||
@@ -4124,7 +4130,7 @@ Value& Path::make(Value& root) const {
|
||||
|
||||
#if !defined(isnan)
|
||||
// IEEE standard states that NaN values will not compare to themselves
|
||||
#define isnan(x) (x != x)
|
||||
#define isnan(x) ((x) != (x))
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
@@ -4210,16 +4216,18 @@ String valueToString(double value, bool useSpecialFloats,
|
||||
|
||||
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
|
||||
|
||||
// strip the zero padding from the right
|
||||
if (precisionType == PrecisionType::decimalPlaces) {
|
||||
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
|
||||
}
|
||||
|
||||
// try to ensure we preserve the fact that this was given to us as a double on
|
||||
// input
|
||||
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
|
||||
buffer += ".0";
|
||||
}
|
||||
|
||||
// strip the zero padding from the right
|
||||
if (precisionType == PrecisionType::decimalPlaces) {
|
||||
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision),
|
||||
buffer.end());
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
} // namespace
|
||||
@@ -4231,11 +4239,11 @@ String valueToString(double value, unsigned int precision,
|
||||
|
||||
String valueToString(bool value) { return value ? "true" : "false"; }
|
||||
|
||||
static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
|
||||
static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
|
||||
assert(s || !n);
|
||||
|
||||
return std::any_of(s, s + n, [](unsigned char c) {
|
||||
return c == '\\' || c == '"' || !std::isprint(c);
|
||||
return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4326,12 +4334,12 @@ static void appendHex(String& result, unsigned ch) {
|
||||
result.append("\\u").append(toHex16Bit(ch));
|
||||
}
|
||||
|
||||
static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
static String valueToQuotedStringN(const char* value, size_t length,
|
||||
bool emitUTF8 = false) {
|
||||
if (value == nullptr)
|
||||
return "";
|
||||
|
||||
if (!isAnyCharRequiredQuoting(value, length))
|
||||
if (!doesAnyCharRequireEscaping(value, length))
|
||||
return String("\"") + value + "\"";
|
||||
// We have to walk value and escape any special characters.
|
||||
// Appending to String is not efficient, but this should be rare.
|
||||
@@ -4404,7 +4412,7 @@ static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
}
|
||||
|
||||
String valueToQuotedString(const char* value) {
|
||||
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
|
||||
return valueToQuotedStringN(value, strlen(value));
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
@@ -4453,7 +4461,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
|
||||
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
|
||||
break;
|
||||
}
|
||||
case booleanValue:
|
||||
@@ -4476,8 +4484,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
const String& name = *it;
|
||||
if (it != members.begin())
|
||||
document_ += ',';
|
||||
document_ += valueToQuotedStringN(name.data(),
|
||||
static_cast<unsigned>(name.length()));
|
||||
document_ += valueToQuotedStringN(name.data(), name.length());
|
||||
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
||||
writeValue(value[name]);
|
||||
}
|
||||
@@ -4522,7 +4529,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -4563,7 +4570,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
}
|
||||
|
||||
void StyledWriter::writeArrayValue(const Value& value) {
|
||||
unsigned size = value.size();
|
||||
size_t size = value.size();
|
||||
if (size == 0)
|
||||
pushValue("[]");
|
||||
else {
|
||||
@@ -4572,7 +4579,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
writeWithIndent("[");
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index = 0;
|
||||
ArrayIndex index = 0;
|
||||
for (;;) {
|
||||
const Value& childValue = value[index];
|
||||
writeCommentBeforeValue(childValue);
|
||||
@@ -4595,7 +4602,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
{
|
||||
assert(childValues_.size() == size);
|
||||
document_ += "[ ";
|
||||
for (unsigned index = 0; index < size; ++index) {
|
||||
for (size_t index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
@@ -4740,7 +4747,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -5014,8 +5021,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
|
||||
emitUTF8_));
|
||||
pushValue(
|
||||
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -5038,8 +5045,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
String const& name = *it;
|
||||
Value const& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedStringN(
|
||||
name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
|
||||
writeWithIndent(
|
||||
valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
|
||||
*sout_ << colonSymbol_;
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
@@ -5273,7 +5280,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const {
|
||||
if (valid_keys.count(key))
|
||||
continue;
|
||||
if (invalid)
|
||||
(*invalid)[std::move(key)] = *si;
|
||||
(*invalid)[key] = *si;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.6.220404001" targetFramework="native" />
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.2-prerelease.220406002" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3-prerelease.220816001" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220201.1" targetFramework="native" developmentDependency="true" />
|
||||
|
||||
<!-- Managed packages -->
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"description": "Controls how 'intense' text is rendered when unfocused. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
@@ -366,6 +366,10 @@
|
||||
"quit",
|
||||
"adjustOpacity",
|
||||
"restoreLastClosed",
|
||||
"addMark",
|
||||
"scrollToMark",
|
||||
"clearMark",
|
||||
"clearAllMarks",
|
||||
"unbound"
|
||||
],
|
||||
"type": "string"
|
||||
@@ -385,6 +389,15 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ScrollToMarkDirection": {
|
||||
"enum": [
|
||||
"previous",
|
||||
"next",
|
||||
"first",
|
||||
"last"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ResizeDirection": {
|
||||
"enum": [
|
||||
"left",
|
||||
@@ -734,6 +747,30 @@
|
||||
"direction"
|
||||
]
|
||||
},
|
||||
"ScrollToMarkAction": {
|
||||
"description": "Arguments corresponding to a Scroll to Mark Action",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "scrollToMark"
|
||||
},
|
||||
"direction": {
|
||||
"$ref": "#/$defs/ScrollToMarkDirection",
|
||||
"default": "previous",
|
||||
"description": "The direction to scroll to a mark."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [
|
||||
"direction"
|
||||
]
|
||||
},
|
||||
"SendInputAction": {
|
||||
"description": "Arguments corresponding to a Send Input Action",
|
||||
"allOf": [
|
||||
@@ -841,6 +878,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"AddMarkAction": {
|
||||
"description": "Arguments corresponding to an Add Mark Action",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "addMark"
|
||||
},
|
||||
"color": {
|
||||
"$ref": "#/$defs/Color",
|
||||
"default": null,
|
||||
"description": "If provided, will set the mark's color to the given value."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"SetColorSchemeAction": {
|
||||
"description": "Arguments corresponding to a Set Color Scheme Action",
|
||||
"allOf": [
|
||||
@@ -1669,6 +1727,16 @@
|
||||
"description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.autoMarkPrompts": {
|
||||
"default": false,
|
||||
"description": "When set to true, prompts will automatically be marked.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.showMarksOnScrollbar": {
|
||||
"default": false,
|
||||
"description": "When set to true, marks added to the buffer via the addMark action will appear on the scrollbar.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableAnimations": {
|
||||
"default": false,
|
||||
"description": "When set to `true`, visual animations will be disabled across the application.",
|
||||
@@ -2013,15 +2081,20 @@
|
||||
"description": "Controls what happens when the application emits a BEL character. When set to \"all\", the Terminal will play a sound, flash the taskbar icon (if the terminal window is not in focus) and flash the window. An array of specific behaviors can also be used. Supported array values include `audible`, `window` and `taskbar`. When set to \"none\", nothing will happen.",
|
||||
"$ref": "#/$defs/BellStyle"
|
||||
},
|
||||
"bellSound": {
|
||||
"description": "Sets the sound played when the application emits a BEL. When set to an array, the terminal will pick one of those sounds at random.",
|
||||
"$ref": "#/$defs/BellSound"
|
||||
},
|
||||
"closeOnExit": {
|
||||
"default": "graceful",
|
||||
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",
|
||||
"default": "automatic",
|
||||
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"automatic\" (behave as \"graceful\" only for processes launched by terminal, behave as \"always\" otherwise)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
"never",
|
||||
"graceful",
|
||||
"always"
|
||||
"always",
|
||||
"automatic"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2136,6 +2209,17 @@
|
||||
],
|
||||
"deprecated": true
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
"bright",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"foreground": {
|
||||
"$ref": "#/$defs/Color",
|
||||
"default": "#cccccc",
|
||||
@@ -2231,7 +2315,10 @@
|
||||
},
|
||||
"startingDirectory": {
|
||||
"description": "The directory the shell starts in when it is loaded.",
|
||||
"type": "string"
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"suppressApplicationTitle": {
|
||||
"description": "When set to true, tabTitle overrides the default title of the tab and any title change messages from the application will be suppressed. When set to false, tabTitle behaves as normal.",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
||||
namespace interval_tree
|
||||
|
||||
@@ -8,7 +8,7 @@ That provenance file is automatically read and inventoried by Microsoft systems
|
||||
|
||||
## What should be done to update this in the future?
|
||||
|
||||
1. Go to ekg/intervaltreerepository on GitHub.
|
||||
1. Go to the ekg/intervaltree repository on GitHub.
|
||||
2. Take the file IntervalTree.h wholesale and drop it into the directory here.
|
||||
3. Don't change anything about it.
|
||||
4. Validate that the license in the root of the repository didn't change and update it if so. It is sitting in the same directory as this readme.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/ekg/intervaltree",
|
||||
"commitHash": "b90527f9e6d51cd36ecbb50429e4524d3a418ea5"
|
||||
"commitHash": "aa5937755000f1cd007402d03b6f7ce4427c5d21"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{"Registrations":[
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/component-detection-manifest.json",
|
||||
"Registrations": [
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/kimwalisch/libpopcnt",
|
||||
"commitHash": "043a99fba31121a70bcb2f589faa17f534ae6085"
|
||||
}
|
||||
}
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/kimwalisch/libpopcnt",
|
||||
"commitHash": "c49987e90e56191c399cab881ab87b5daecc9b8e"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.1" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.1" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -5,121 +5,125 @@
|
||||
#include "MidiAudio.hpp"
|
||||
#include "../terminal/parser/stateMachine.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class MidiOut
|
||||
{
|
||||
public:
|
||||
static constexpr auto NOTE_OFF = 0x80;
|
||||
static constexpr auto NOTE_ON = 0x90;
|
||||
static constexpr auto PROGRAM_CHANGE = 0xC0;
|
||||
|
||||
// We're using a square wave as an approximation of the sound that the
|
||||
// original VT525 terminals might have produced. This is probably not
|
||||
// quite right, but it works reasonably well.
|
||||
static constexpr auto SQUARE_WAVE_SYNTH = 80;
|
||||
|
||||
MidiOut() noexcept
|
||||
{
|
||||
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
|
||||
{
|
||||
midiOutOpen(&handle, MIDI_MAPPER, NULL, NULL, CALLBACK_NULL);
|
||||
OutputMessage(PROGRAM_CHANGE, SQUARE_WAVE_SYNTH);
|
||||
}
|
||||
}
|
||||
~MidiOut() noexcept
|
||||
{
|
||||
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
|
||||
{
|
||||
midiOutClose(handle);
|
||||
}
|
||||
}
|
||||
void OutputMessage(const int b1, const int b2, const int b3 = 0, const int b4 = 0) noexcept
|
||||
{
|
||||
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
|
||||
{
|
||||
midiOutShortMsg(handle, MAKELONG(MAKEWORD(b1, b2), MAKEWORD(b3, b4)));
|
||||
}
|
||||
}
|
||||
|
||||
MidiOut(const MidiOut&) = delete;
|
||||
MidiOut(MidiOut&&) = delete;
|
||||
MidiOut& operator=(const MidiOut&) = delete;
|
||||
MidiOut& operator=(MidiOut&&) = delete;
|
||||
|
||||
private:
|
||||
HMIDIOUT handle = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
MidiAudio::~MidiAudio() noexcept
|
||||
// The WAVE_DATA below is an 8-bit PCM encoding of a triangle wave form.
|
||||
// We just play this on repeat at varying frequencies to produce our notes.
|
||||
constexpr auto WAVE_SIZE = 16u;
|
||||
constexpr auto WAVE_DATA = std::array<byte, WAVE_SIZE>{ 128, 159, 191, 223, 255, 223, 191, 159, 128, 96, 64, 32, 0, 32, 64, 96 };
|
||||
|
||||
void MidiAudio::_initialize(HWND windowHandle) noexcept
|
||||
{
|
||||
try
|
||||
_hwnd = windowHandle;
|
||||
_directSoundModule.reset(LoadLibraryExW(L"dsound.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
|
||||
if (_directSoundModule)
|
||||
{
|
||||
#pragma warning(suppress : 26447)
|
||||
// We acquire the lock here so the class isn't destroyed while in use.
|
||||
// If this throws, we'll catch it, so the C26447 warning is bogus.
|
||||
_inUseMutex.lock();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If the lock fails, we'll just have to live with the consequences.
|
||||
if (const auto createFunction = GetProcAddressByFunctionDeclaration(_directSoundModule.get(), DirectSoundCreate8))
|
||||
{
|
||||
if (SUCCEEDED(createFunction(nullptr, &_directSound, nullptr)))
|
||||
{
|
||||
if (SUCCEEDED(_directSound->SetCooperativeLevel(windowHandle, DSSCL_NORMAL)))
|
||||
{
|
||||
_createBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MidiAudio::Initialize()
|
||||
void MidiAudio::BeginSkip() noexcept
|
||||
{
|
||||
_shutdownFuture = _shutdownPromise.get_future();
|
||||
_skip.SetEvent();
|
||||
}
|
||||
|
||||
void MidiAudio::Shutdown()
|
||||
void MidiAudio::EndSkip() noexcept
|
||||
{
|
||||
// Once the shutdown promise is set, any note that is playing will stop
|
||||
// immediately, and the Unlock call will exit the thread ASAP.
|
||||
_shutdownPromise.set_value();
|
||||
_skip.ResetEvent();
|
||||
}
|
||||
|
||||
void MidiAudio::Lock()
|
||||
{
|
||||
_inUseMutex.lock();
|
||||
}
|
||||
|
||||
void MidiAudio::Unlock()
|
||||
{
|
||||
// We need to check the shutdown status before releasing the mutex,
|
||||
// because after that the class could be destroyed.
|
||||
const auto shutdownStatus = _shutdownFuture.wait_for(0s);
|
||||
_inUseMutex.unlock();
|
||||
// If the wait didn't timeout, that means the shutdown promise was set,
|
||||
// so we need to exit the thread ASAP by throwing an exception.
|
||||
if (shutdownStatus != std::future_status::timeout)
|
||||
{
|
||||
throw Microsoft::Console::VirtualTerminal::StateMachine::ShutdownException{};
|
||||
}
|
||||
}
|
||||
|
||||
void MidiAudio::PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept
|
||||
void MidiAudio::PlayNote(HWND windowHandle, const int noteNumber, const int velocity, const std::chrono::milliseconds duration) noexcept
|
||||
try
|
||||
{
|
||||
// The MidiOut is a local static because we can only have one instance,
|
||||
// and we only want to construct it when it's actually needed.
|
||||
static MidiOut midiOut;
|
||||
|
||||
if (velocity)
|
||||
if (_skip.is_signaled())
|
||||
{
|
||||
midiOut.OutputMessage(MidiOut::NOTE_ON, noteNumber, velocity);
|
||||
return;
|
||||
}
|
||||
|
||||
// By waiting on the shutdown future with the duration of the note, we'll
|
||||
// either be paused for the appropriate amount of time, or we'll break out
|
||||
// of the wait early if we've been shutdown.
|
||||
_shutdownFuture.wait_for(duration);
|
||||
|
||||
if (velocity)
|
||||
if (_hwnd != windowHandle)
|
||||
{
|
||||
midiOut.OutputMessage(MidiOut::NOTE_OFF, noteNumber, velocity);
|
||||
_initialize(windowHandle);
|
||||
}
|
||||
|
||||
const auto& buffer = _buffers.at(_activeBufferIndex);
|
||||
if (velocity && buffer)
|
||||
{
|
||||
// The formula for frequency is 2^(n/12) * 440Hz, where n is zero for
|
||||
// the A above middle C (A4). In MIDI terms, A4 is note number 69,
|
||||
// which is why we subtract 69. We also need to multiply by the size
|
||||
// of the wave form to determine the frequency that the sound buffer
|
||||
// has to be played to achieve the equivalent note frequency.
|
||||
const auto frequency = std::pow(2.0, (noteNumber - 69.0) / 12.0) * 440.0 * WAVE_SIZE;
|
||||
buffer->SetFrequency(gsl::narrow_cast<DWORD>(frequency));
|
||||
// For the volume, we're using the formula defined in the the General
|
||||
// MIDI Level 2 specification: Gain in dB = 40 * log10(v/127). We need
|
||||
// to multiply by 4000, though, because the SetVolume method expects
|
||||
// the volume to be in hundredths of a decibel.
|
||||
const auto volume = 4000.0 * std::log10(velocity / 127.0);
|
||||
buffer->SetVolume(gsl::narrow_cast<LONG>(volume));
|
||||
// Resetting the buffer to a position that is slightly off from the
|
||||
// last position will help to produce a clearer separation between
|
||||
// tones when repeating sequences of the same note.
|
||||
buffer->SetCurrentPosition((_lastBufferPosition + 12) % WAVE_SIZE);
|
||||
}
|
||||
|
||||
// By waiting on the skip event with a maximum duration of the note, we'll
|
||||
// either be paused for the appropriate amount of time, or we'll break out early
|
||||
// because BeginSkip() was called. This happens for Ctrl+C or during shutdown.
|
||||
_skip.wait(::base::saturated_cast<DWORD>(duration.count()));
|
||||
|
||||
if (velocity && buffer)
|
||||
{
|
||||
// When the note ends, we just turn the volume down instead of stopping
|
||||
// the sound buffer. This helps reduce unwanted static between notes.
|
||||
buffer->SetVolume(DSBVOLUME_MIN);
|
||||
buffer->GetCurrentPosition(&_lastBufferPosition, nullptr);
|
||||
}
|
||||
|
||||
// Cycling between multiple buffers can also help reduce the static.
|
||||
_activeBufferIndex = (_activeBufferIndex + 1) % _buffers.size();
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
void MidiAudio::_createBuffers() noexcept
|
||||
{
|
||||
auto waveFormat = WAVEFORMATEX{};
|
||||
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
waveFormat.nChannels = 1;
|
||||
waveFormat.nSamplesPerSec = 8000;
|
||||
waveFormat.wBitsPerSample = 8;
|
||||
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
|
||||
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
|
||||
|
||||
auto bufferDescription = DSBUFFERDESC{};
|
||||
bufferDescription.dwSize = sizeof(DSBUFFERDESC);
|
||||
bufferDescription.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS;
|
||||
bufferDescription.dwBufferBytes = WAVE_SIZE;
|
||||
bufferDescription.lpwfxFormat = &waveFormat;
|
||||
|
||||
for (auto& buffer : _buffers)
|
||||
{
|
||||
if (SUCCEEDED(_directSound->CreateSoundBuffer(&bufferDescription, &buffer, nullptr)))
|
||||
{
|
||||
LPVOID bufferPtr;
|
||||
DWORD bufferSize;
|
||||
if (SUCCEEDED(buffer->Lock(0, 0, &bufferPtr, &bufferSize, nullptr, nullptr, DSBLOCK_ENTIREBUFFER)))
|
||||
{
|
||||
std::memcpy(bufferPtr, WAVE_DATA.data(), WAVE_DATA.size());
|
||||
buffer->Unlock(bufferPtr, bufferSize, nullptr, 0);
|
||||
}
|
||||
buffer->SetVolume(DSBVOLUME_MIN);
|
||||
buffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,26 +11,28 @@ Abstract:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <array>
|
||||
|
||||
struct IDirectSound8;
|
||||
struct IDirectSoundBuffer;
|
||||
|
||||
class MidiAudio
|
||||
{
|
||||
public:
|
||||
MidiAudio() = default;
|
||||
MidiAudio(const MidiAudio&) = delete;
|
||||
MidiAudio(MidiAudio&&) = delete;
|
||||
MidiAudio& operator=(const MidiAudio&) = delete;
|
||||
MidiAudio& operator=(MidiAudio&&) = delete;
|
||||
~MidiAudio() noexcept;
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
void PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept;
|
||||
void BeginSkip() noexcept;
|
||||
void EndSkip() noexcept;
|
||||
void PlayNote(HWND windowHandle, const int noteNumber, const int velocity, const std::chrono::milliseconds duration) noexcept;
|
||||
|
||||
private:
|
||||
std::promise<void> _shutdownPromise;
|
||||
std::future<void> _shutdownFuture;
|
||||
std::mutex _inUseMutex;
|
||||
void _initialize(HWND windowHandle) noexcept;
|
||||
void _createBuffers() noexcept;
|
||||
|
||||
wil::slim_event_manual_reset _skip;
|
||||
|
||||
HWND _hwnd = nullptr;
|
||||
wil::unique_hmodule _directSoundModule;
|
||||
wil::com_ptr<IDirectSound8> _directSound;
|
||||
std::array<wil::com_ptr<IDirectSoundBuffer>, 2> _buffers;
|
||||
size_t _activeBufferIndex = 0;
|
||||
DWORD _lastBufferPosition = 0;
|
||||
};
|
||||
|
||||
@@ -25,7 +25,9 @@ Abstract:
|
||||
#endif
|
||||
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <mmeapi.h>
|
||||
#include <dsound.h>
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -357,11 +357,6 @@ void TextAttribute::SetReverseVideo(bool isReversed) noexcept
|
||||
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO, isReversed);
|
||||
}
|
||||
|
||||
ExtendedAttributes TextAttribute::GetExtendedAttributes() const noexcept
|
||||
{
|
||||
return _extendedAttrs;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - swaps foreground and background color
|
||||
void TextAttribute::Invert() noexcept
|
||||
|
||||
@@ -109,7 +109,10 @@ public:
|
||||
void SetOverlined(bool isOverlined) noexcept;
|
||||
void SetReverseVideo(bool isReversed) noexcept;
|
||||
|
||||
ExtendedAttributes GetExtendedAttributes() const noexcept;
|
||||
constexpr ExtendedAttributes GetExtendedAttributes() const noexcept
|
||||
{
|
||||
return _extendedAttrs;
|
||||
}
|
||||
|
||||
bool IsHyperlink() const noexcept;
|
||||
|
||||
@@ -161,6 +164,13 @@ public:
|
||||
{
|
||||
return WI_IsAnyFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_UNDERSCORE);
|
||||
}
|
||||
constexpr bool HasAnyExtendedAttributes() const noexcept
|
||||
{
|
||||
return GetExtendedAttributes() != ExtendedAttributes::Normal ||
|
||||
IsAnyGridLineEnabled() ||
|
||||
GetHyperlinkId() != 0 ||
|
||||
IsReverseVideo();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::array<TextColor, 16> s_legacyForegroundColorMap;
|
||||
|
||||
@@ -30,7 +30,7 @@ using PointTree = interval_tree::IntervalTree<til::point, size_t>;
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
// Note: may throw exception
|
||||
TextBuffer::TextBuffer(const til::size screenBufferSize,
|
||||
TextBuffer::TextBuffer(til::size screenBufferSize,
|
||||
const TextAttribute defaultAttributes,
|
||||
const UINT cursorSize,
|
||||
const bool isActiveBuffer,
|
||||
@@ -46,6 +46,10 @@ TextBuffer::TextBuffer(const til::size screenBufferSize,
|
||||
_currentHyperlinkId{ 1 },
|
||||
_currentPatternId{ 0 }
|
||||
{
|
||||
// Guard against resizing the text buffer to 0 columns/rows, which would break being able to insert text.
|
||||
screenBufferSize.width = std::max(screenBufferSize.width, 1);
|
||||
screenBufferSize.height = std::max(screenBufferSize.height, 1);
|
||||
|
||||
// initialize ROWs
|
||||
_storage.reserve(gsl::narrow<size_t>(screenBufferSize.Y));
|
||||
for (til::CoordType i = 0; i < screenBufferSize.Y; ++i)
|
||||
@@ -896,9 +900,11 @@ void TextBuffer::Reset()
|
||||
// - 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(const til::size newSize) noexcept
|
||||
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(til::size newSize) noexcept
|
||||
{
|
||||
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
|
||||
// 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
|
||||
{
|
||||
@@ -1032,6 +1038,7 @@ void TextBuffer::_RefreshRowIDs(std::optional<til::CoordType> newRowWidth)
|
||||
{
|
||||
std::unordered_map<til::CoordType, til::CoordType> rowMap;
|
||||
til::CoordType i = 0;
|
||||
til::CoordType newWidth = newRowWidth.value_or(_storage.at(0).size());
|
||||
for (auto& it : _storage)
|
||||
{
|
||||
// Build a map so we can update Unicode Storage
|
||||
@@ -1043,12 +1050,13 @@ void TextBuffer::_RefreshRowIDs(std::optional<til::CoordType> newRowWidth)
|
||||
// Also update the char row parent pointers as they can get shuffled up in the rotates.
|
||||
it.GetCharRow().UpdateParent(&it);
|
||||
|
||||
// Resize the rows in the X dimension if we have a new width
|
||||
if (newRowWidth.has_value())
|
||||
{
|
||||
// Realloc in the X direction
|
||||
THROW_IF_FAILED(it.Resize(newRowWidth.value()));
|
||||
}
|
||||
// Realloc in the X direction
|
||||
// BODGY: We unpack the optional early and resize here unconditionally
|
||||
// due to a codegen issue in LKG14. We used to check the optional in
|
||||
// every iteration of the loop, but that resulted in the optimizer
|
||||
// emitting a copy of the loop, used when the optional was empty, that
|
||||
// never exited. Oops.
|
||||
THROW_IF_FAILED(it.Resize(newWidth));
|
||||
}
|
||||
|
||||
// Give the new mapping to Unicode Storage
|
||||
@@ -1138,7 +1146,7 @@ til::point TextBuffer::GetWordStart(const til::point target, const std::wstring_
|
||||
// that it actually points to a space in the buffer
|
||||
copy = bufferSize.BottomRightInclusive();
|
||||
}
|
||||
else if (target >= limit)
|
||||
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
// if at/past the limit --> clamp to limit
|
||||
copy = limitOptional.value_or(bufferSize.BottomRightInclusive());
|
||||
@@ -1254,7 +1262,7 @@ til::point TextBuffer::GetWordEnd(const til::point target, const std::wstring_vi
|
||||
// Already at/past the limit. Can't move forward.
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
if (target >= limit)
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
@@ -1282,7 +1290,7 @@ til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, cons
|
||||
const auto bufferSize{ GetSize() };
|
||||
auto result{ target };
|
||||
|
||||
if (target >= limit)
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
// if we're already on/past the last RegularChar,
|
||||
// clamp result to that position
|
||||
@@ -1419,7 +1427,7 @@ bool TextBuffer::MoveToNextWord(til::point& pos, const std::wstring_view wordDel
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
|
||||
|
||||
if (copy >= limit)
|
||||
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1466,7 +1474,7 @@ til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::po
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
// Clamp pos to limit
|
||||
if (resultPos > limit)
|
||||
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
|
||||
{
|
||||
resultPos = limit;
|
||||
}
|
||||
@@ -1494,7 +1502,7 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
// Clamp pos to limit
|
||||
if (resultPos > limit)
|
||||
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
|
||||
{
|
||||
resultPos = limit;
|
||||
}
|
||||
@@ -1524,19 +1532,9 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
|
||||
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
bool pastEndInclusive;
|
||||
til::point limit;
|
||||
{
|
||||
// if the limit is past the end of the buffer,
|
||||
// 1) clamp limit to end of buffer
|
||||
// 2) set pastEndInclusive
|
||||
const auto endInclusive{ bufferSize.BottomRightInclusive() };
|
||||
const auto val = limitOptional.value_or(endInclusive);
|
||||
pastEndInclusive = val > endInclusive;
|
||||
limit = pastEndInclusive ? endInclusive : val;
|
||||
}
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit) + (pastEndInclusive ? 1 : 0) };
|
||||
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) };
|
||||
if (distanceToLimit >= 0)
|
||||
{
|
||||
// Corner Case: we're on/past the limit
|
||||
@@ -1579,7 +1577,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
|
||||
const auto bufferSize = GetSize();
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
if (pos > limit)
|
||||
if (bufferSize.CompareInBounds(pos, limit, true) > 0)
|
||||
{
|
||||
// we're past the end
|
||||
// clamp us to the limit
|
||||
@@ -1621,7 +1619,7 @@ const std::vector<til::inclusive_rect> TextBuffer::GetTextRects(til::point start
|
||||
// (0,0) is the top-left of the screen
|
||||
// the physically "higher" coordinate is closer to the top-left
|
||||
// the physically "lower" coordinate is closer to the bottom-right
|
||||
const auto [higherCoord, lowerCoord] = start <= end ?
|
||||
const auto [higherCoord, lowerCoord] = bufferSize.CompareInBounds(start, end) <= 0 ?
|
||||
std::make_tuple(start, end) :
|
||||
std::make_tuple(end, start);
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.pre.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<!--
|
||||
These two properties are very important!
|
||||
@@ -164,13 +169,7 @@
|
||||
</Target>
|
||||
|
||||
<!-- This is required to get the package dependency in the AppXManifest. -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="DEC4804D-56D1-4F73-9FBE-6828E7C85C56" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -188,7 +188,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="1833E661-CC81-4DD0-87C6-C2F74BD39EFA" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -188,7 +188,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -503,7 +503,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -521,7 +521,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -843,7 +843,7 @@ namespace TerminalAppLocalTests
|
||||
// | 1 | 2 |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
secondId = tab->_activePane->Id().value();
|
||||
});
|
||||
Sleep(250);
|
||||
@@ -861,7 +861,7 @@ namespace TerminalAppLocalTests
|
||||
// | 3 | |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
// Split again to make the 3rd tab
|
||||
thirdId = tab->_activePane->Id().value();
|
||||
@@ -881,7 +881,7 @@ namespace TerminalAppLocalTests
|
||||
// | 3 | 4 |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
fourthId = tab->_activePane->Id().value();
|
||||
});
|
||||
|
||||
@@ -30,14 +30,6 @@
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<Import Project="$(OpenConsoleDir)\src\cppwinrt.build.pre.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "HwndTerminal.hpp"
|
||||
#include <windowsx.h>
|
||||
#include "../../types/TermControlUiaProvider.hpp"
|
||||
#include <DefaultSettings.h>
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../../types/viewport.cpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
@@ -54,6 +50,17 @@ LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc(
|
||||
LPARAM lParam) noexcept
|
||||
try
|
||||
{
|
||||
if (WM_NCCREATE == uMsg)
|
||||
{
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
auto cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
HwndTerminal* that = static_cast<HwndTerminal*>(cs->lpCreateParams);
|
||||
that->_hwnd = wil::unique_hwnd(hwnd);
|
||||
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
|
||||
return DefWindowProc(hwnd, WM_NCCREATE, wParam, lParam);
|
||||
}
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
auto terminal = reinterpret_cast<HwndTerminal*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
|
||||
@@ -182,7 +189,7 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
|
||||
if (RegisterTermClass(hInstance))
|
||||
{
|
||||
_hwnd = wil::unique_hwnd(CreateWindowExW(
|
||||
CreateWindowExW(
|
||||
0,
|
||||
term_window_class,
|
||||
nullptr,
|
||||
@@ -197,10 +204,7 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
parentHwnd,
|
||||
nullptr,
|
||||
hInstance,
|
||||
nullptr));
|
||||
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
SetWindowLongPtr(_hwnd.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,14 +328,15 @@ IRawElementProviderSimple* HwndTerminal::_GetUiaProvider() noexcept
|
||||
{
|
||||
// If TermControlUiaProvider throws during construction,
|
||||
// we don't want to try constructing an instance again and again.
|
||||
// _uiaProviderInitialized helps us prevent this.
|
||||
if (!_uiaProviderInitialized)
|
||||
if (!_uiaProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaProviderInitialized = true;
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<HwndTerminalAutomationPeer>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(_uiaProvider.Get());
|
||||
LOG_IF_FAILED(_uiaEngine->Enable());
|
||||
_renderer->AddRenderEngine(_uiaEngine.get());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -360,15 +365,20 @@ HRESULT HwndTerminal::Refresh(const til::size windowSize, _Out_ til::size* dimen
|
||||
const auto viewInPixels = Viewport::FromDimensions(windowSize);
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
|
||||
// Guard against resizing the window to 0 columns/rows, which the text buffer classes don't really support.
|
||||
auto size = vp.Dimensions();
|
||||
size.width = std::max(size.width, 1);
|
||||
size.height = std::max(size.height, 1);
|
||||
|
||||
// If this function succeeds with S_FALSE, then the terminal didn't
|
||||
// actually change size. No need to notify the connection of this
|
||||
// no-op.
|
||||
// TODO: MSFT:20642295 Resizing the buffer will corrupt it
|
||||
// I believe we'll need support for CSI 2J, and additionally I think
|
||||
// we're resetting the viewport to the top
|
||||
RETURN_IF_FAILED(_terminal->UserResize({ vp.Width(), vp.Height() }));
|
||||
dimensions->X = vp.Width();
|
||||
dimensions->Y = vp.Height();
|
||||
RETURN_IF_FAILED(_terminal->UserResize(size));
|
||||
dimensions->width = size.width;
|
||||
dimensions->height = size.height;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -380,29 +390,10 @@ void HwndTerminal::SendOutput(std::wstring_view data)
|
||||
|
||||
HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal)
|
||||
{
|
||||
// In order for UIA to hook up properly there needs to be a "static" window hosting the
|
||||
// inner win32 control. If the static window is not present then WM_GETOBJECT messages
|
||||
// will not reach the child control, and the uia element will not be present in the tree.
|
||||
auto _hostWindow = CreateWindowEx(
|
||||
0,
|
||||
L"static",
|
||||
nullptr,
|
||||
WS_CHILD |
|
||||
WS_CLIPCHILDREN |
|
||||
WS_CLIPSIBLINGS |
|
||||
WS_VISIBLE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
parentHwnd,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
auto _terminal = std::make_unique<HwndTerminal>(_hostWindow);
|
||||
auto _terminal = std::make_unique<HwndTerminal>(parentHwnd);
|
||||
RETURN_IF_FAILED(_terminal->Initialize());
|
||||
|
||||
*hwnd = _hostWindow;
|
||||
*hwnd = _terminal->GetHwnd();
|
||||
*terminal = _terminal.release();
|
||||
|
||||
return S_OK;
|
||||
@@ -487,7 +478,7 @@ HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ til::CoordTyp
|
||||
{
|
||||
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
|
||||
|
||||
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, { width, height });
|
||||
const auto viewInPixels = Viewport::FromDimensions({ width, height });
|
||||
const auto viewInCharacters = publicTerminal->_renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
|
||||
dimensions->X = viewInCharacters.Width();
|
||||
@@ -725,6 +716,10 @@ try
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
if (vkey && keyDown && _uiaProvider)
|
||||
{
|
||||
_uiaProvider->RecordKeyEvent(vkey);
|
||||
}
|
||||
_terminal->SendKeyEvent(vkey, scanCode, modifiers, keyDown);
|
||||
}
|
||||
CATCH_LOG();
|
||||
@@ -833,12 +828,20 @@ void __stdcall TerminalSetFocus(void* terminal)
|
||||
{
|
||||
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
|
||||
publicTerminal->_focused = true;
|
||||
if (auto uiaEngine = publicTerminal->_uiaEngine.get())
|
||||
{
|
||||
LOG_IF_FAILED(uiaEngine->Enable());
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall TerminalKillFocus(void* terminal)
|
||||
{
|
||||
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
|
||||
publicTerminal->_focused = false;
|
||||
if (auto uiaEngine = publicTerminal->_uiaEngine.get())
|
||||
{
|
||||
LOG_IF_FAILED(uiaEngine->Disable());
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include <UIAutomationCore.h>
|
||||
#include "../../types/IControlAccessibilityInfo.h"
|
||||
#include "../../types/TermControlUiaProvider.hpp"
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
@@ -74,15 +74,15 @@ private:
|
||||
FontInfo _actualFont;
|
||||
int _currentDpi;
|
||||
std::function<void(wchar_t*)> _pfnWriteCallback;
|
||||
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
|
||||
::Microsoft::WRL::ComPtr<HwndTerminalAutomationPeer> _uiaProvider;
|
||||
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal;
|
||||
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer;
|
||||
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine;
|
||||
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
|
||||
|
||||
bool _focused{ false };
|
||||
bool _uiaProviderInitialized{ false };
|
||||
|
||||
std::chrono::milliseconds _multiClickTime;
|
||||
unsigned int _multiClickCounter{};
|
||||
|
||||
159
src/cascadia/PublicTerminalCore/HwndTerminalAutomationPeer.cpp
Normal file
159
src/cascadia/PublicTerminalCore/HwndTerminalAutomationPeer.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
#include "../../types/UiaTracing.h"
|
||||
#include <UIAutomationCoreApi.h>
|
||||
|
||||
#pragma warning(suppress : 4471) // We don't control UIAutomationClient
|
||||
#include <UIAutomationClient.h>
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
static constexpr wchar_t UNICODE_NEWLINE{ L'\n' };
|
||||
|
||||
// Method Description:
|
||||
// - creates a copy of the provided text with all of the control characters removed
|
||||
// Arguments:
|
||||
// - text: the string we're sanitizing
|
||||
// Return Value:
|
||||
// - a copy of "sanitized" with all of the control characters removed
|
||||
static std::wstring Sanitize(std::wstring_view text)
|
||||
{
|
||||
std::wstring sanitized{ text };
|
||||
sanitized.erase(std::remove_if(sanitized.begin(), sanitized.end(), [](wchar_t c) {
|
||||
return (c < UNICODE_SPACE && c != UNICODE_NEWLINE) || c == 0x7F /*DEL*/;
|
||||
}),
|
||||
sanitized.end());
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - verifies if a given string has text that would be read by a screen reader.
|
||||
// - a string of control characters, for example, would not be read.
|
||||
// Arguments:
|
||||
// - text: the string we're validating
|
||||
// Return Value:
|
||||
// - true, if the text is readable. false, otherwise.
|
||||
static constexpr bool IsReadable(std::wstring_view text)
|
||||
{
|
||||
for (const auto c : text)
|
||||
{
|
||||
if (c > UNICODE_SPACE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HwndTerminalAutomationPeer::RecordKeyEvent(const WORD vkey)
|
||||
{
|
||||
if (const auto charCode{ MapVirtualKey(vkey, MAPVK_VK_TO_CHAR) })
|
||||
{
|
||||
if (const auto keyEventChar{ gsl::narrow_cast<wchar_t>(charCode) }; IsReadable({ &keyEventChar, 1 }))
|
||||
{
|
||||
_keyEvents.emplace_back(keyEventChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of IRawElementProviderSimple::get_PropertyValue.
|
||||
// Gets custom properties.
|
||||
IFACEMETHODIMP HwndTerminalAutomationPeer::GetPropertyValue(_In_ PROPERTYID propertyId,
|
||||
_Out_ VARIANT* pVariant) noexcept
|
||||
{
|
||||
pVariant->vt = VT_EMPTY;
|
||||
|
||||
// Returning the default will leave the property as the default
|
||||
// so we only really need to touch it for the properties we want to implement
|
||||
if (propertyId == UIA_ClassNamePropertyId)
|
||||
{
|
||||
// IMPORTANT: Do NOT change the name. Screen readers like may be dependent on this being "WpfTermControl".
|
||||
pVariant->bstrVal = SysAllocString(L"WPFTermControl");
|
||||
if (pVariant->bstrVal != nullptr)
|
||||
{
|
||||
pVariant->vt = VT_BSTR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fall back to shared implementation
|
||||
return TermControlUiaProvider::GetPropertyValue(propertyId, pVariant);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's selection has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalSelectionChanged()
|
||||
{
|
||||
UiaTracing::Signal::SelectionChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's output has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalTextChanged()
|
||||
{
|
||||
UiaTracing::Signal::TextChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextChangedEventId));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the cursor's state has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalCursorChanged()
|
||||
{
|
||||
UiaTracing::Signal::CursorChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId));
|
||||
}
|
||||
|
||||
void HwndTerminalAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
|
||||
{
|
||||
// Try to suppress any events (or event data)
|
||||
// that is just the keypress the user made
|
||||
auto sanitized{ Sanitize(newOutput) };
|
||||
while (!_keyEvents.empty() && IsReadable(sanitized))
|
||||
{
|
||||
if (til::toupper_ascii(sanitized.front()) == _keyEvents.front())
|
||||
{
|
||||
// the key event's character (i.e. the "A" key) matches
|
||||
// the output character (i.e. "a" or "A" text).
|
||||
// We can assume that the output character resulted from
|
||||
// the pressed key, so we can ignore it.
|
||||
sanitized = sanitized.substr(1);
|
||||
_keyEvents.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The output doesn't match,
|
||||
// so clear the input stack and
|
||||
// move on to fire the event.
|
||||
_keyEvents.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress event if the remaining text is not readable
|
||||
if (!IsReadable(sanitized))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sanitizedBstr = wil::make_bstr_nothrow(sanitized.c_str());
|
||||
static auto activityId = wil::make_bstr_nothrow(L"TerminalTextOutput");
|
||||
LOG_IF_FAILED(UiaRaiseNotificationEvent(this, NotificationKind_ActionCompleted, NotificationProcessing_All, sanitizedBstr.get(), activityId.get()));
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- HwndTerminalAutomationPeer.hpp
|
||||
|
||||
Abstract:
|
||||
- This module provides UI Automation access to the HwndTerminal
|
||||
to support both automation tests and accessibility (screen
|
||||
reading) applications. This mainly interacts with TermControlUiaProvider
|
||||
to allow for shared code with Windows Terminal accessibility providers.
|
||||
|
||||
Author(s):
|
||||
- Carlos Zamora (CaZamor) 2022
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../types/TermControlUiaProvider.hpp"
|
||||
#include "../types/IUiaEventDispatcher.h"
|
||||
#include "../types/IControlAccessibilityInfo.h"
|
||||
|
||||
class HwndTerminalAutomationPeer :
|
||||
public ::Microsoft::Console::Types::IUiaEventDispatcher,
|
||||
public ::Microsoft::Terminal::TermControlUiaProvider
|
||||
{
|
||||
public:
|
||||
void RecordKeyEvent(const WORD vkey);
|
||||
|
||||
IFACEMETHODIMP GetPropertyValue(_In_ PROPERTYID idProp,
|
||||
_Out_ VARIANT* pVariant) noexcept override;
|
||||
|
||||
#pragma region IUiaEventDispatcher
|
||||
void SignalSelectionChanged() override;
|
||||
void SignalTextChanged() override;
|
||||
void SignalCursorChanged() override;
|
||||
void NotifyNewOutput(std::wstring_view newOutput) override;
|
||||
#pragma endregion
|
||||
private:
|
||||
std::deque<wchar_t> _keyEvents;
|
||||
};
|
||||
@@ -15,9 +15,11 @@
|
||||
<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>
|
||||
@@ -42,6 +44,9 @@
|
||||
<ProjectReference Include="$(SolutionDir)src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj">
|
||||
<Project>{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf63}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<ClCompile Include="HwndTerminal.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
@@ -32,5 +35,8 @@
|
||||
<ClInclude Include="HwndTerminal.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -9,3 +9,4 @@
|
||||
#endif
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
#include <UIAutomationCore.h>
|
||||
@@ -103,6 +103,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
auto proposedCommandline = false;
|
||||
Remoting::ProposeCommandlineResult result{ nullptr };
|
||||
auto attempts = 0;
|
||||
while (!proposedCommandline)
|
||||
{
|
||||
try
|
||||
@@ -118,78 +119,78 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
proposedCommandline = true;
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
catch (...)
|
||||
{
|
||||
// We did not successfully ask the king what to do. They
|
||||
// hopefully just died here. That's okay, let's just go ask the
|
||||
// next in the line of succession. At the very worst, we'll find
|
||||
// _us_, (likely last in the line).
|
||||
// We did not successfully ask the king what to do. This could
|
||||
// be for many reasons. Most commonly, the monarch died as we
|
||||
// were talking to it. That could be a RPC_SERVER_UNAVAILABLE_HR
|
||||
// or RPC_CALL_FAILED_HR (GH#12666). We also saw a
|
||||
// RPC_S_CALL_FAILED_DNE in GH#11790. Ultimately, if this is
|
||||
// gonna fail, we want to just try again, regardless of the
|
||||
// cause. That's why we're no longer checking what the exception
|
||||
// was, we're just always gonna try again regardless.
|
||||
//
|
||||
// If the king returned some _other_ error here, than lets
|
||||
// bubble that up because that's a real issue.
|
||||
//
|
||||
// I'm checking both these here. I had previously got a
|
||||
// RPC_S_CALL_FAILED about here once.
|
||||
if (e.code() == RPC_SERVER_UNAVAILABLE_HR || e.code() == RPC_CALL_FAILED_HR)
|
||||
// They hopefully just died here. That's okay, let's just go
|
||||
// ask the next in the line of succession. At the very worst,
|
||||
// we'll find _us_, (likely last in the line).
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_unexpectedExceptionFromKing",
|
||||
TraceLoggingInt32(attempts, "attempts", "How many times we've tried"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
attempts++;
|
||||
|
||||
if (attempts >= 10)
|
||||
{
|
||||
// We've tried 10 times to find the monarch, failing each
|
||||
// time. Since we have no idea why, we're guessing that in
|
||||
// this case, there's just a Monarch registered that's
|
||||
// misbehaving. In this case, just fall back to
|
||||
// "IsolatedMonarchMode" - we can't trust the currently
|
||||
// registered one.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_kingDied",
|
||||
"WindowManager_TooManyAttempts_NullMonarchIsolateMode",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_monarch = winrt::make<winrt::Microsoft::Terminal::Remoting::implementation::Monarch>();
|
||||
_createCallbacks();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We failed to ask the monarch. It must have died. Try and
|
||||
// find the real monarch. Don't perform an election, that
|
||||
// assumes we have a peasant, which we don't yet.
|
||||
_createMonarchAndCallbacks();
|
||||
// _createMonarchAndCallbacks will initialize _isKing
|
||||
if (_isKing)
|
||||
{
|
||||
// We became the king. We don't need to ProposeCommandline to ourself, we're just
|
||||
// going to do it.
|
||||
//
|
||||
// Return early, because there's nothing else for us to do here.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_becameKing",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// In WindowManager::ProposeCommandline, had we been the
|
||||
// king originally, we would have started by setting
|
||||
// this to true. We became the monarch here, so set it
|
||||
// here as well.
|
||||
_shouldCreateWindow = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Here, we created the new monarch, it wasn't us, so we're
|
||||
// gonna go through the while loop again and ask the new
|
||||
// king.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_tryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
if (_isKing)
|
||||
{
|
||||
// We became the king. We don't need to ProposeCommandline to ourself, we're just
|
||||
// going to do it.
|
||||
//
|
||||
// Return early, because there's nothing else for us to do here.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_unexpectedResultFromKing",
|
||||
"WindowManager_proposeToMonarch_becameKing",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
throw;
|
||||
|
||||
// In WindowManager::ProposeCommandline, had we been the
|
||||
// king originally, we would have started by setting
|
||||
// this to true. We became the monarch here, so set it
|
||||
// here as well.
|
||||
_shouldCreateWindow = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If the monarch (maybe us) failed for _any other reason_ than
|
||||
// them dying. This IS quite unexpected. Let this bubble out.
|
||||
|
||||
// Here, we created the new monarch, it wasn't us, so we're
|
||||
// gonna go through the while loop again and ask the new
|
||||
// king.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_unexpectedExceptionFromKing",
|
||||
"WindowManager_proposeToMonarch_tryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,15 +346,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
CLSCTX_LOCAL_SERVER);
|
||||
}
|
||||
|
||||
// NOTE: This can throw! Callers include:
|
||||
// - the constructor, who performs this in a loop until it successfully
|
||||
// find a a monarch
|
||||
// - the performElection method, which is called in the waitOnMonarch
|
||||
// thread. All the calls in that thread are wrapped in try/catch's
|
||||
// already.
|
||||
// - _createOurPeasant, who might do this in a loop to establish us with the
|
||||
// monarch.
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
// Tries to instantiate a monarch, tries again, and eventually either throws
|
||||
// (so that the caller will try again) or falls back to the isolated
|
||||
// monarch.
|
||||
void WindowManager::_redundantCreateMonarch()
|
||||
{
|
||||
_createMonarch();
|
||||
|
||||
@@ -399,9 +395,26 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
winrt::hresult_error(E_UNEXPECTED, L"Did not expect the Monarch to ever be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This can throw! Callers include:
|
||||
// - the constructor, who performs this in a loop until it successfully
|
||||
// find a a monarch
|
||||
// - the performElection method, which is called in the waitOnMonarch
|
||||
// thread. All the calls in that thread are wrapped in try/catch's
|
||||
// already.
|
||||
// - _createOurPeasant, who might do this in a loop to establish us with the
|
||||
// monarch.
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
{
|
||||
_redundantCreateMonarch();
|
||||
// We're pretty confident that we have a Monarch here.
|
||||
_createCallbacks();
|
||||
}
|
||||
|
||||
// Check if we became the king, and if we are, wire up callbacks.
|
||||
void WindowManager::_createCallbacks()
|
||||
{
|
||||
// Save the result of checking if we're the king. We want to avoid
|
||||
// unnecessary calls back and forth if we can.
|
||||
_isKing = _areWeTheKing();
|
||||
|
||||
@@ -72,7 +72,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
void _registerAsMonarch();
|
||||
void _createMonarch();
|
||||
void _redundantCreateMonarch();
|
||||
void _createMonarchAndCallbacks();
|
||||
void _createCallbacks();
|
||||
bool _areWeTheKing();
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant(std::optional<uint64_t> givenID,
|
||||
const winrt::hstring& givenName);
|
||||
|
||||
@@ -25,37 +25,25 @@ static constexpr std::wstring_view VerbName{ L"WindowsTerminalOpenHere" };
|
||||
// failure from an earlier HRESULT.
|
||||
HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
IBindCtx* /*pBindContext*/)
|
||||
try
|
||||
{
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
|
||||
if (!psi)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
wil::unique_cotaskmem_string pszName;
|
||||
|
||||
if (psiItemArray == nullptr)
|
||||
{
|
||||
// get the current path from explorer.exe
|
||||
const auto path = this->_GetPathFromExplorer();
|
||||
|
||||
// no go, unable to get a reasonable path
|
||||
if (path.empty())
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
pszName = wil::make_cotaskmem_string(path.c_str(), path.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD count;
|
||||
psiItemArray->GetCount(&count);
|
||||
|
||||
winrt::com_ptr<IShellItem> psi;
|
||||
RETURN_IF_FAILED(psiItemArray->GetItemAt(0, psi.put()));
|
||||
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
|
||||
}
|
||||
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
|
||||
|
||||
{
|
||||
wil::unique_process_information _piClient;
|
||||
STARTUPINFOEX siEx{ 0 };
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()) };
|
||||
std::wstring cmdline;
|
||||
RETURN_IF_FAILED(wil::str_printf_nothrow(cmdline, LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr, // lpApplicationName
|
||||
cmdline.data(),
|
||||
@@ -72,6 +60,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
HRESULT OpenTerminalHere::GetToolTip(IShellItemArray* /*psiItemArray*/,
|
||||
LPWSTR* ppszInfoTip)
|
||||
@@ -109,22 +98,14 @@ HRESULT OpenTerminalHere::GetState(IShellItemArray* psiItemArray,
|
||||
// We however don't need to bother with any of that.
|
||||
|
||||
// If no item was selected when the context menu was opened and Explorer
|
||||
// is not at a valid path (e.g. This PC or Quick Access), we should hide
|
||||
// is not at a valid location (e.g. This PC or Quick Access), we should hide
|
||||
// the verb from the context menu.
|
||||
if (psiItemArray == nullptr)
|
||||
{
|
||||
const auto path = this->_GetPathFromExplorer();
|
||||
*pCmdState = path.empty() ? ECS_HIDDEN : ECS_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
winrt::com_ptr<IShellItem> psi;
|
||||
psiItemArray->GetItemAt(0, psi.put());
|
||||
SFGAOF attributes;
|
||||
const bool isFileSystemItem = (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
|
||||
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
|
||||
}
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
|
||||
|
||||
SFGAOF attributes;
|
||||
const bool isFileSystemItem = psi && (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
|
||||
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -160,102 +141,54 @@ HRESULT OpenTerminalHere::EnumSubCommands(IEnumExplorerCommand** ppEnum)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
std::wstring OpenTerminalHere::_GetPathFromExplorer() const
|
||||
IFACEMETHODIMP OpenTerminalHere::SetSite(IUnknown* site) noexcept
|
||||
{
|
||||
using namespace std;
|
||||
using namespace winrt;
|
||||
|
||||
wstring path;
|
||||
HRESULT hr = NOERROR;
|
||||
|
||||
auto hwnd = ::GetForegroundWindow();
|
||||
if (hwnd == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
TCHAR szName[MAX_PATH] = { 0 };
|
||||
::GetClassName(hwnd, szName, MAX_PATH);
|
||||
if (0 == StrCmp(szName, L"WorkerW") ||
|
||||
0 == StrCmp(szName, L"Progman"))
|
||||
{
|
||||
//special folder: desktop
|
||||
hr = ::SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, szName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
path = szName;
|
||||
return path;
|
||||
}
|
||||
|
||||
if (0 != StrCmp(szName, L"CabinetWClass"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
com_ptr<IShellWindows> shell;
|
||||
try
|
||||
{
|
||||
shell = create_instance<IShellWindows>(CLSID_ShellWindows, CLSCTX_ALL);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//look like try_create_instance is not available no more
|
||||
}
|
||||
|
||||
if (shell == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
com_ptr<IDispatch> disp;
|
||||
wil::unique_variant variant;
|
||||
variant.vt = VT_I4;
|
||||
|
||||
com_ptr<IWebBrowserApp> browser;
|
||||
// look for correct explorer window
|
||||
for (variant.intVal = 0;
|
||||
shell->Item(variant, disp.put()) == S_OK;
|
||||
variant.intVal++)
|
||||
{
|
||||
com_ptr<IWebBrowserApp> tmp;
|
||||
if (FAILED(disp->QueryInterface(tmp.put())))
|
||||
{
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
continue;
|
||||
}
|
||||
|
||||
HWND tmpHWND = NULL;
|
||||
hr = tmp->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&tmpHWND));
|
||||
if (hwnd == tmpHWND)
|
||||
{
|
||||
browser = tmp;
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
break; //found
|
||||
}
|
||||
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
}
|
||||
|
||||
if (browser != nullptr)
|
||||
{
|
||||
wil::unique_bstr url;
|
||||
hr = browser->get_LocationURL(&url);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
wstring sUrl(url.get(), SysStringLen(url.get()));
|
||||
DWORD size = MAX_PATH;
|
||||
hr = ::PathCreateFromUrl(sUrl.c_str(), szName, &size, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
path = szName;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
site_ = site;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OpenTerminalHere::GetSite(REFIID riid, void** site) noexcept
|
||||
{
|
||||
RETURN_IF_FAILED(site_.query_to(riid, site));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetLocationFromSite(IShellItem** location) const noexcept
|
||||
{
|
||||
wil::assign_null_to_opt_param(location);
|
||||
|
||||
if (!site_)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IServiceProvider> serviceProvider;
|
||||
RETURN_IF_FAILED(site_.query_to(serviceProvider.put()));
|
||||
wil::com_ptr_nothrow<IFolderView> folderView;
|
||||
RETURN_IF_FAILED(serviceProvider->QueryService(SID_SFolderView, IID_PPV_ARGS(folderView.put())));
|
||||
RETURN_IF_FAILED(folderView->GetFolder(IID_PPV_ARGS(location)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept
|
||||
{
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
if (psiArray)
|
||||
{
|
||||
DWORD count{};
|
||||
RETURN_IF_FAILED(psiArray->GetCount(&count));
|
||||
if (count) // Sometimes we get an array with a count of 0. Fall back to the site chain.
|
||||
{
|
||||
RETURN_IF_FAILED(psiArray->GetItemAt(0, psi.put()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!psi)
|
||||
{
|
||||
RETURN_IF_FAILED(GetLocationFromSite(psi.put()));
|
||||
}
|
||||
|
||||
RETURN_HR_IF(S_FALSE, !psi);
|
||||
RETURN_IF_FAILED(psi.copy_to(location));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ Author(s):
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include <conattrs.hpp>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
struct
|
||||
@@ -34,7 +32,7 @@ struct
|
||||
#else // DEV
|
||||
__declspec(uuid("52065414-e077-47ec-a3ac-1cc5455e1b54"))
|
||||
#endif
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand>
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand, IObjectWithSite>
|
||||
{
|
||||
#pragma region IExplorerCommand
|
||||
STDMETHODIMP Invoke(IShellItemArray* psiItemArray,
|
||||
@@ -52,9 +50,16 @@ struct
|
||||
STDMETHODIMP GetCanonicalName(GUID* pguidCommandName);
|
||||
STDMETHODIMP EnumSubCommands(IEnumExplorerCommand** ppEnum);
|
||||
#pragma endregion
|
||||
#pragma region IObjectWithSite
|
||||
IFACEMETHODIMP SetSite(IUnknown* site) noexcept;
|
||||
IFACEMETHODIMP GetSite(REFIID riid, void** site) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
std::wstring _GetPathFromExplorer() const;
|
||||
HRESULT GetLocationFromSite(IShellItem** location) const noexcept;
|
||||
HRESULT GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept;
|
||||
|
||||
wil::com_ptr_nothrow<IUnknown> site_;
|
||||
};
|
||||
|
||||
CoCreatableClass(OpenTerminalHere);
|
||||
|
||||
@@ -201,10 +201,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
const auto& duplicateFromTab{ realArgs.SplitMode() == SplitType::Duplicate ? _GetFocusedTab() : nullptr };
|
||||
_SplitPane(realArgs.SplitDirection(),
|
||||
// This is safe, we're already filtering so the value is (0, 1)
|
||||
::base::saturated_cast<float>(realArgs.SplitSize()),
|
||||
_MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
|
||||
_MakePane(realArgs.TerminalArgs(), duplicateFromTab));
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -606,7 +607,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
activeTab->ActivateColorPicker();
|
||||
activeTab->RequestColorPicker();
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <WtExeUtils.h>
|
||||
#include <wil/token_helpers.h >
|
||||
#include <wil/token_helpers.h>
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
@@ -292,10 +292,36 @@ namespace winrt::TerminalApp::implementation
|
||||
_root->Maximized(true);
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode))
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode) && !IsQuakeWindow())
|
||||
{
|
||||
_root->SetFullscreen(true);
|
||||
}
|
||||
|
||||
FILETIME creationTime, exitTime, kernelTime, userTime, now;
|
||||
if (GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime, &userTime))
|
||||
{
|
||||
static constexpr auto asInteger = [](const FILETIME& f) {
|
||||
ULARGE_INTEGER i;
|
||||
i.LowPart = f.dwLowDateTime;
|
||||
i.HighPart = f.dwHighDateTime;
|
||||
return i.QuadPart;
|
||||
};
|
||||
static constexpr auto asSeconds = [](uint64_t v) {
|
||||
return v * 1e-7f;
|
||||
};
|
||||
|
||||
GetSystemTimeAsFileTime(&now);
|
||||
|
||||
const auto latency = asSeconds(asInteger(now) - asInteger(creationTime));
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppInitialized",
|
||||
TraceLoggingDescription("Event emitted once the app is initialized"),
|
||||
TraceLoggingFloat32(latency, "latency"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
});
|
||||
_root->Create();
|
||||
|
||||
@@ -312,7 +338,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingDescription("Event emitted when the application is started"),
|
||||
TraceLoggingBool(_settings.GlobalSettings().ShowTabsInTitlebar(), "TabsInTitlebar"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
void AppLogic::Quit()
|
||||
@@ -504,26 +530,8 @@ namespace winrt::TerminalApp::implementation
|
||||
if (keyboardServiceIsDisabled)
|
||||
{
|
||||
_root->ShowKeyboardServiceWarning();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"KeyboardServiceWasDisabled",
|
||||
TraceLoggingDescription("Event emitted when the keyboard service is disabled, and we warned them about it"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For when the warning was disabled in the settings
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"KeyboardServiceWarningWasDisabledBySetting",
|
||||
TraceLoggingDescription("Event emitted when the user has disabled the KB service warning"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
|
||||
if (FAILED(_settingsLoadedResult))
|
||||
{
|
||||
@@ -557,7 +565,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// not be noisy with this dialog if we failed for some reason.
|
||||
|
||||
// Open the service manager. This will return 0 if it failed.
|
||||
wil::unique_schandle hManager{ OpenSCManager(nullptr, nullptr, 0) };
|
||||
wil::unique_schandle hManager{ OpenSCManagerW(nullptr, nullptr, 0) };
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!hManager.is_valid()))
|
||||
{
|
||||
@@ -565,8 +573,12 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Get a handle to the keyboard service
|
||||
wil::unique_schandle hService{ OpenService(hManager.get(), TabletInputServiceKey.data(), SERVICE_QUERY_STATUS) };
|
||||
if (LOG_LAST_ERROR_IF(!hService.is_valid()))
|
||||
wil::unique_schandle hService{ OpenServiceW(hManager.get(), TabletInputServiceKey.data(), SERVICE_QUERY_STATUS) };
|
||||
|
||||
// Windows 11 doesn't have a TabletInputService.
|
||||
// (It was renamed to TextInputManagementService, because people kept thinking that a
|
||||
// service called "tablet-something" is system-irrelevant on PCs and can be disabled.)
|
||||
if (!hService.is_valid())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -851,15 +863,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// happening during startup, it'll need to happen on a background thread.
|
||||
void AppLogic::LoadSettings()
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"SettingsLoadStarted",
|
||||
TraceLoggingDescription("Event emitted before loading the settings"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
// Attempt to load the settings.
|
||||
// If it fails,
|
||||
// - use Default settings,
|
||||
@@ -875,17 +878,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_settings = CascadiaSettings::LoadDefaults();
|
||||
}
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> delta = end - start;
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"SettingsLoadComplete",
|
||||
TraceLoggingDescription("Event emitted when loading the settings is finished"),
|
||||
TraceLoggingFloat64(delta.count(), "Duration"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
_loadedInitialSettings = true;
|
||||
|
||||
// Register for directory change notification.
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingDescription("Event emitted when the Command Palette is opened"),
|
||||
TraceLoggingWideString(L"Action", "Mode", "which mode the palette was opened in"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -474,7 +474,13 @@ namespace winrt::TerminalApp::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedElementOrAncestor = Input::FocusManager::GetFocusedElement(this->XamlRoot()).try_as<DependencyObject>();
|
||||
auto root = this->XamlRoot();
|
||||
if (!root)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedElementOrAncestor = Input::FocusManager::GetFocusedElement(root).try_as<DependencyObject>();
|
||||
while (focusedElementOrAncestor)
|
||||
{
|
||||
if (focusedElementOrAncestor == *this)
|
||||
@@ -524,6 +530,34 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::_listItemSelectionChanged(const Windows::Foundation::IInspectable& /*sender*/, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e)
|
||||
{
|
||||
// We don't care about...
|
||||
// - CommandlineMode: it doesn't have any selectable items in the list view
|
||||
// - TabSwitchMode: focus and selected item are in sync
|
||||
if (_currentMode == CommandPaletteMode::ActionMode || _currentMode == CommandPaletteMode::TabSearchMode)
|
||||
{
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(_searchBox()) })
|
||||
{
|
||||
if (const auto selectedList = e.AddedItems(); selectedList.Size() > 0)
|
||||
{
|
||||
const auto selectedCommand = selectedList.GetAt(0);
|
||||
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
|
||||
{
|
||||
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
Automation::Peers::AutomationNotificationKind::ItemAdded,
|
||||
Automation::Peers::AutomationNotificationProcessing::MostRecent,
|
||||
paletteItem.Name() + L" " + paletteItem.KeyChordText(),
|
||||
L"CommandPaletteSelectedItemChanged" /* unique name for this notification category */);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// This event is called when the user clicks on an ChevronLeft button right
|
||||
// next to the ParentCommandName (e.g. New Tab...) above the subcommands list.
|
||||
@@ -677,7 +711,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingUInt32(searchTextLength, "SearchTextLength", "Number of characters in the search string"),
|
||||
TraceLoggingUInt32(nestedCommandDepth, "NestedCommandDepth", "the depth in the tree of commands for the dispatched action"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,7 +779,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"CommandPaletteDispatchedCommandline",
|
||||
TraceLoggingDescription("Event emitted when the user runs a commandline in the Command Palette"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
|
||||
{
|
||||
@@ -783,7 +817,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"CommandPaletteDismissed",
|
||||
TraceLoggingDescription("Event emitted when the user dismisses the Command Palette without selecting an action"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -92,6 +92,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _listItemClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::ItemClickEventArgs& e);
|
||||
|
||||
void _listItemSelectionChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e);
|
||||
|
||||
void _moveBackButtonClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs&);
|
||||
|
||||
void _updateFilteredActions();
|
||||
|
||||
@@ -402,6 +402,7 @@
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="_listItemClicked"
|
||||
ItemsSource="{x:Bind FilteredActions}"
|
||||
SelectionChanged="_listItemSelectionChanged"
|
||||
SelectionMode="Single" />
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -111,7 +111,15 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
|
||||
void DebugTapConnection::_OutputHandler(const hstring str)
|
||||
{
|
||||
_TerminalOutputHandlers(til::visualize_control_codes(str));
|
||||
auto output = til::visualize_control_codes(str);
|
||||
// To make the output easier to read, we introduce a line break whenever
|
||||
// an LF control is encountered. But at this point, the LF would have
|
||||
// been converted to U+240A (␊), so that's what we need to search for.
|
||||
for (size_t lfPos = 0; (lfPos = output.find(L'\u240A', lfPos)) != std::wstring::npos;)
|
||||
{
|
||||
output.insert(++lfPos, L"\r\n");
|
||||
}
|
||||
_TerminalOutputHandlers(output);
|
||||
}
|
||||
|
||||
// Called by the DebugInputTapConnection to print user input
|
||||
|
||||
@@ -89,12 +89,8 @@ winrt::fire_and_forget Jumplist::UpdateJumplist(const CascadiaSettings& settings
|
||||
winrt::com_ptr<IObjectCollection> jumplistItems;
|
||||
jumplistItems.capture(jumplistInstance, &ICustomDestinationList::BeginList, &slots);
|
||||
|
||||
// It's easier to clear the list and re-add everything. The settings aren't
|
||||
// updated often, and there likely isn't a huge amount of items to add.
|
||||
THROW_IF_FAILED(jumplistItems->Clear());
|
||||
|
||||
// Update the list of profiles.
|
||||
THROW_IF_FAILED(_updateProfiles(jumplistItems.get(), strongSettings.ActiveProfiles().GetView()));
|
||||
_updateProfiles(jumplistItems.get(), strongSettings.ActiveProfiles().GetView());
|
||||
|
||||
// TODO GH#1571: Add items from the future customizable new tab dropdown as well.
|
||||
// This could either replace the default profiles, or be added alongside them.
|
||||
@@ -116,26 +112,22 @@ winrt::fire_and_forget Jumplist::UpdateJumplist(const CascadiaSettings& settings
|
||||
// - profiles - The profiles to add to the jumplist
|
||||
// Return Value:
|
||||
// - S_OK or HRESULT failure code.
|
||||
[[nodiscard]] HRESULT Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<Profile> profiles) noexcept
|
||||
void Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<Profile> profiles)
|
||||
{
|
||||
try
|
||||
// It's easier to clear the list and re-add everything. The settings aren't
|
||||
// updated often, and there likely isn't a huge amount of items to add.
|
||||
THROW_IF_FAILED(jumplistItems->Clear());
|
||||
|
||||
for (const auto& profile : profiles)
|
||||
{
|
||||
for (const auto& profile : profiles)
|
||||
{
|
||||
// Craft the arguments following "wt.exe"
|
||||
auto args = fmt::format(L"-p {}", to_hstring(profile.Guid()));
|
||||
// Craft the arguments following "wt.exe"
|
||||
auto args = fmt::format(L"-p {}", to_hstring(profile.Guid()));
|
||||
|
||||
// Create the shell link object for the profile
|
||||
winrt::com_ptr<IShellLinkW> shLink;
|
||||
const auto normalizedIconPath{ _normalizeIconPath(profile.Icon()) };
|
||||
RETURN_IF_FAILED(_createShellLink(profile.Name(), normalizedIconPath, args, shLink.put()));
|
||||
|
||||
RETURN_IF_FAILED(jumplistItems->AddObject(shLink.get()));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
// Create the shell link object for the profile
|
||||
const auto normalizedIconPath{ _normalizeIconPath(profile.Icon()) };
|
||||
const auto shLink = _createShellLink(profile.Name(), normalizedIconPath, args);
|
||||
THROW_IF_FAILED(jumplistItems->AddObject(shLink.get()));
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -150,36 +142,27 @@ winrt::fire_and_forget Jumplist::UpdateJumplist(const CascadiaSettings& settings
|
||||
// - shLink: The shell link object to return.
|
||||
// Return Value:
|
||||
// - S_OK or HRESULT failure code.
|
||||
[[nodiscard]] HRESULT Jumplist::_createShellLink(const std::wstring_view name,
|
||||
const std::wstring_view path,
|
||||
const std::wstring_view args,
|
||||
IShellLinkW** shLink) noexcept
|
||||
winrt::com_ptr<IShellLinkW> Jumplist::_createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto sh = winrt::create_instance<IShellLinkW>(CLSID_ShellLink, CLSCTX_ALL);
|
||||
auto sh = winrt::create_instance<IShellLinkW>(CLSID_ShellLink, CLSCTX_ALL);
|
||||
|
||||
const auto module{ GetWtExePath() };
|
||||
RETURN_IF_FAILED(sh->SetPath(module.data()));
|
||||
RETURN_IF_FAILED(sh->SetArguments(args.data()));
|
||||
const auto module{ GetWtExePath() };
|
||||
THROW_IF_FAILED(sh->SetPath(module.data()));
|
||||
THROW_IF_FAILED(sh->SetArguments(args.data()));
|
||||
|
||||
PROPVARIANT titleProp;
|
||||
titleProp.vt = VT_LPWSTR;
|
||||
titleProp.pwszVal = const_cast<wchar_t*>(name.data());
|
||||
PROPVARIANT titleProp;
|
||||
titleProp.vt = VT_LPWSTR;
|
||||
titleProp.pwszVal = const_cast<wchar_t*>(name.data());
|
||||
|
||||
PROPVARIANT iconProp;
|
||||
iconProp.vt = VT_LPWSTR;
|
||||
iconProp.pwszVal = const_cast<wchar_t*>(path.data());
|
||||
PROPVARIANT iconProp;
|
||||
iconProp.vt = VT_LPWSTR;
|
||||
iconProp.pwszVal = const_cast<wchar_t*>(path.data());
|
||||
|
||||
auto propStore{ sh.as<IPropertyStore>() };
|
||||
RETURN_IF_FAILED(propStore->SetValue(PKEY_Title, titleProp));
|
||||
RETURN_IF_FAILED(propStore->SetValue(PKEY_AppUserModel_DestListLogoUri, iconProp));
|
||||
auto propStore{ sh.as<IPropertyStore>() };
|
||||
THROW_IF_FAILED(propStore->SetValue(PKEY_Title, titleProp));
|
||||
THROW_IF_FAILED(propStore->SetValue(PKEY_AppUserModel_DestListLogoUri, iconProp));
|
||||
|
||||
RETURN_IF_FAILED(propStore->Commit());
|
||||
THROW_IF_FAILED(propStore->Commit());
|
||||
|
||||
*shLink = sh.detach();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
return sh;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ public:
|
||||
static winrt::fire_and_forget UpdateJumplist(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) noexcept;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static HRESULT _updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Settings::Model::Profile> profiles) noexcept;
|
||||
[[nodiscard]] static HRESULT _createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args, IShellLinkW** shLink) noexcept;
|
||||
static void _updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Settings::Model::Profile> profiles);
|
||||
static winrt::com_ptr<IShellLinkW> _createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args);
|
||||
};
|
||||
|
||||
@@ -20,70 +20,73 @@
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="CloseButtonColor">#C42B1C</Color>
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="CaptionButtonStroke"
|
||||
<StaticResource x:Key="CaptionButtonForeground"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokeColor"
|
||||
<StaticResource x:Key="CaptionButtonForegroundColor"
|
||||
ResourceKey="SystemBaseHighColor" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="Transparent" />
|
||||
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed"
|
||||
Opacity="0.9"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPressed"
|
||||
Opacity="0.7"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackground"
|
||||
Color="#00e81123" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
|
||||
Color="#00C42B1C" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00C42B1C</Color>
|
||||
|
||||
<StaticResource x:Key="RestoreButtonGlyph"
|
||||
ResourceKey="RestoreGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="CloseButtonColor">#C42B1C</Color>
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="CaptionButtonStroke"
|
||||
<StaticResource x:Key="CaptionButtonForeground"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokeColor"
|
||||
<StaticResource x:Key="CaptionButtonForegroundColor"
|
||||
ResourceKey="SystemBaseHighColor" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="Transparent" />
|
||||
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed"
|
||||
Opacity="0.9"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPressed"
|
||||
Opacity="0.7"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackground"
|
||||
Color="#00e81123" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
|
||||
Color="#00C42B1C" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00C42B1C</Color>
|
||||
|
||||
<StaticResource x:Key="RestoreButtonGlyph"
|
||||
ResourceKey="RestoreGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">2.0</x:Double>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="{ThemeResource SystemColorButtonFaceColor}" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor"
|
||||
@@ -92,32 +95,43 @@
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonStroke"
|
||||
<SolidColorBrush x:Key="CaptionButtonForeground"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<StaticResource x:Key="CaptionButtonStrokeColor"
|
||||
<StaticResource x:Key="CaptionButtonForegroundColor"
|
||||
ResourceKey="SystemColorButtonTextColor" />
|
||||
<SolidColorBrush x:Key="CaptionButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
|
||||
<StaticResource x:Key="RestoreButtonGlyph"
|
||||
ResourceKey="RestoreGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<!--
|
||||
These strings need to be initialized to something, so they're
|
||||
just initialized to the path for the close button. Each specific
|
||||
button should override them as needed.
|
||||
Initializes the string to the close button glyph.
|
||||
Each specific button overrides it as needed.
|
||||
-->
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
<x:String x:Key="CaptionButtonGlyph"></x:String>
|
||||
|
||||
<x:String x:Key="MinimizeGlyph"></x:String>
|
||||
<x:String x:Key="MaximizeGlyph"></x:String>
|
||||
<x:String x:Key="RestoreGlyph"></x:String>
|
||||
<x:String x:Key="CloseGlyph"></x:String>
|
||||
|
||||
<x:String x:Key="MinimizeGlyphContrast"></x:String>
|
||||
<x:String x:Key="MaximizeGlyphContrast"></x:String>
|
||||
<x:String x:Key="RestoreGlyphContrast"></x:String>
|
||||
<x:String x:Key="CloseGlyphContrast"></x:String>
|
||||
|
||||
<!--
|
||||
"CaptionButtonHeightWindowed" and
|
||||
@@ -151,16 +165,13 @@
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Path x:Name="Path"
|
||||
Width="10"
|
||||
Height="10"
|
||||
Data="{ThemeResource CaptionButtonPath}"
|
||||
Stretch="Fill"
|
||||
Stroke="{ThemeResource CaptionButtonStroke}"
|
||||
StrokeEndLineCap="Square"
|
||||
StrokeStartLineCap="Square"
|
||||
StrokeThickness="{ThemeResource CaptionButtonStrokeWidth}"
|
||||
UseLayoutRounding="True" />
|
||||
<Viewbox Width="10"
|
||||
Height="10">
|
||||
<FontIcon x:Name="ButtonIcon"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Foreground="{ThemeResource CaptionButtonForeground}"
|
||||
Glyph="{ThemeResource CaptionButtonGlyph}" />
|
||||
</Viewbox>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
@@ -172,9 +183,9 @@
|
||||
Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonBackgroundColor}"
|
||||
Duration="0:0:0.15" />
|
||||
<ColorAnimation Storyboard.TargetName="Path"
|
||||
Storyboard.TargetProperty="(UIElement.Stroke).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonStrokeColor}"
|
||||
<ColorAnimation Storyboard.TargetName="ButtonIcon"
|
||||
Storyboard.TargetProperty="(UIElement.Foreground).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonForegroundColor}"
|
||||
Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
@@ -183,21 +194,21 @@
|
||||
<VisualState x:Name="Normal">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackground}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStroke}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForeground}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPointerOver}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStrokePointerOver}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPressed}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStrokePressed}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
@@ -209,7 +220,7 @@
|
||||
|
||||
<VisualState x:Name="WindowStateMaximized">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Path.Data" Value="{ThemeResource CaptionButtonPathWindowMaximized}" />
|
||||
<Setter Target="ButtonIcon.Glyph" Value="{ThemeResource RestoreButtonGlyph}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
@@ -235,7 +246,20 @@
|
||||
Style="{StaticResource CaptionButton}">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 H 10</x:String>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MinimizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MinimizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MinimizeGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -253,10 +277,21 @@
|
||||
Click="_MaximizeClick"
|
||||
Style="{StaticResource CaptionButton}">
|
||||
<Button.Resources>
|
||||
<!-- These paths are complicated, but taken directly from WinUI's WindowCaptionButton paths. -->
|
||||
<ResourceDictionary>
|
||||
<x:String x:Key="CaptionButtonPath">M 1.516 -0.001 L 7.451 0.009 C 8.751 0.019 9 1 8.981 1.477 L 9.002 7.558 M 9.002 7.547 C 8.929 8.669 8 9 7.43 9.015 L 1.464 9.005 C 0.374 8.973 0 8 -0.004 7.484 L -0.004 1.477 C 0 1 0.415 0.009 1.527 -0.001</x:String>
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized">M 1.516 -0.001 L 7.451 0.009 C 8.751 0.019 9 1 8.981 1.477 L 9.002 7.558 M 11 6 L 11 2 C 11 0 10 -2 8.011 -1.946 L 7.06 -1.969 L 3 -2 M 9.002 7.547 C 8.929 8.669 8 9 7.43 9.015 L 1.464 9.005 C 0.374 8.973 0 8 -0.004 7.484 L -0.004 1.477 C 0 1 0.415 0.009 1.527 -0.001</x:String>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MaximizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MaximizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MaximizeGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -283,42 +318,46 @@
|
||||
ResourceKey="CloseButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="CloseButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
ResourceKey="CloseButtonStrokePointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
ResourceKey="CloseButtonStrokePressed" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="CloseButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="CloseButtonForegroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonBackground"
|
||||
ResourceKey="CloseButtonBackground" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor"
|
||||
ResourceKey="CloseButtonBackgroundColor" />
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="CloseGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="CloseButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="CloseButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
ResourceKey="CloseButtonStrokePointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
ResourceKey="CloseButtonStrokePressed" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="CloseButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="CloseButtonForegroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonBackground"
|
||||
ResourceKey="CloseButtonBackground" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor"
|
||||
ResourceKey="CloseButtonBackgroundColor" />
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="CloseGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="CloseButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="CloseButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
ResourceKey="CloseButtonStrokePointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
ResourceKey="CloseButtonStrokePressed" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="CloseButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="CloseButtonForegroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="CloseGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
|
||||
@@ -1019,9 +1019,17 @@ void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundatio
|
||||
|
||||
if (_profile)
|
||||
{
|
||||
if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic)
|
||||
{
|
||||
// For 'automatic', we only care about the connection state if we were launched by Terminal
|
||||
// Since we were launched via defterm, ignore the connection state (i.e. we treat the
|
||||
// close on exit mode as 'always', see GH #13325 for discussion)
|
||||
Close();
|
||||
}
|
||||
|
||||
const auto mode = _profile.CloseOnExit();
|
||||
if ((mode == CloseOnExitMode::Always) ||
|
||||
(mode == CloseOnExitMode::Graceful && newConnectionState == ConnectionState::Closed))
|
||||
((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
@@ -1568,11 +1576,12 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
// Find what borders need to persist after we close the child
|
||||
_borders = _GetCommonBorders();
|
||||
|
||||
// take the control, profile and id of the pane that _wasn't_ closed.
|
||||
// take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed.
|
||||
_control = remainingChild->_control;
|
||||
_connectionState = remainingChild->_connectionState;
|
||||
_profile = remainingChild->_profile;
|
||||
_id = remainingChild->Id();
|
||||
_isDefTermSession = remainingChild->_isDefTermSession;
|
||||
|
||||
// Add our new event handler before revoking the old one.
|
||||
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
||||
@@ -2464,11 +2473,12 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move our control, guid into the first one.
|
||||
// Move our control, guid, isDefTermSession into the first one.
|
||||
_firstChild = std::make_shared<Pane>(_profile, _control);
|
||||
_firstChild->_connectionState = std::exchange(_connectionState, ConnectionState::NotConnected);
|
||||
_profile = nullptr;
|
||||
_control = { nullptr };
|
||||
_firstChild->_isDefTermSession = _isDefTermSession;
|
||||
}
|
||||
|
||||
_splitState = actualSplitType;
|
||||
@@ -3108,6 +3118,15 @@ int Pane::GetLeafPaneCount() const noexcept
|
||||
return _IsLeaf() ? 1 : (_firstChild->GetLeafPaneCount() + _secondChild->GetLeafPaneCount());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Should be called when this pane is created via a default terminal handoff
|
||||
// - Finalizes our configuration given the information that we have been
|
||||
// created via default handoff
|
||||
void Pane::FinalizeConfigurationGivenDefault()
|
||||
{
|
||||
_isDefTermSession = true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if the pane or one of its descendants is read-only
|
||||
bool Pane::ContainsReadOnly() const
|
||||
|
||||
@@ -132,6 +132,8 @@ public:
|
||||
bool FocusPane(const std::shared_ptr<Pane> pane);
|
||||
std::shared_ptr<Pane> FindPane(const uint32_t id);
|
||||
|
||||
void FinalizeConfigurationGivenDefault();
|
||||
|
||||
bool ContainsReadOnly() const;
|
||||
|
||||
// Method Description:
|
||||
@@ -212,21 +214,24 @@ private:
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _root{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
|
||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
|
||||
|
||||
#pragma region Properties that need to be transferred between child / parent panes upon splitting / closing
|
||||
std::shared_ptr<Pane> _firstChild{ nullptr };
|
||||
std::shared_ptr<Pane> _secondChild{ nullptr };
|
||||
SplitState _splitState{ SplitState::None };
|
||||
float _desiredSplitPosition;
|
||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
bool _isDefTermSession{ false };
|
||||
#pragma endregion
|
||||
|
||||
std::optional<uint32_t> _id;
|
||||
std::weak_ptr<Pane> _parentChildPath{};
|
||||
|
||||
bool _lastActive{ false };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
winrt::event_token _connectionStateChangedToken{ 0 };
|
||||
winrt::event_token _firstClosedToken{ 0 };
|
||||
winrt::event_token _secondClosedToken{ 0 };
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
</resheader>
|
||||
<data name="AppName" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppNameDev" xml:space="preserve">
|
||||
<value>Terminal Dev</value>
|
||||
@@ -126,9 +127,11 @@
|
||||
</data>
|
||||
<data name="AppNamePre" xml:space="preserve">
|
||||
<value>Terminal Preview</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppStoreName" xml:space="preserve">
|
||||
<value>Windows Terminal</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppStoreNameDev" xml:space="preserve">
|
||||
<value>Windows Terminal Dev</value>
|
||||
@@ -136,9 +139,11 @@
|
||||
</data>
|
||||
<data name="AppStoreNamePre" xml:space="preserve">
|
||||
<value>Windows Terminal Preview</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppShortName" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppShortNameDev" xml:space="preserve">
|
||||
<value>Terminal Dev</value>
|
||||
@@ -146,6 +151,7 @@
|
||||
</data>
|
||||
<data name="AppShortNamePre" xml:space="preserve">
|
||||
<value>Terminal Preview</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppDescription" xml:space="preserve">
|
||||
<value>The New Windows Terminal</value>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "TerminalPage.h"
|
||||
#include "Utils.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "../../inc/til/string.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
@@ -85,34 +86,7 @@ namespace winrt::TerminalApp::implementation
|
||||
//
|
||||
// This call to _MakePane won't return nullptr, we already checked that
|
||||
// case above with the _maybeElevate call.
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
|
||||
|
||||
const auto tabCount = _tabs.Size();
|
||||
const auto usedManualProfile = (newTerminalArgs != nullptr) &&
|
||||
(newTerminalArgs.ProfileIndex() != nullptr ||
|
||||
newTerminalArgs.Profile().empty());
|
||||
|
||||
// Lookup the name of the color scheme used by this profile.
|
||||
const auto scheme = _settings.GetColorSchemeForProfile(profile);
|
||||
// If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
|
||||
// that as the empty string.
|
||||
const auto schemeName = scheme ? scheme.Name() : L"\0";
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
"TabInformation",
|
||||
TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
|
||||
TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
|
||||
TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
|
||||
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
|
||||
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
|
||||
TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
|
||||
TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
|
||||
TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
|
||||
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr, existingConnection));
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
@@ -348,7 +322,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// In the future, it may be preferable to just duplicate the
|
||||
// current control's live settings (which will include changes
|
||||
// made through VT).
|
||||
_CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
|
||||
_CreateNewTabFromPane(_MakePane(nullptr, tab, nullptr));
|
||||
|
||||
const auto runtimeTabText{ tab.GetTabText() };
|
||||
if (!runtimeTabText.empty())
|
||||
@@ -371,7 +345,7 @@ namespace winrt::TerminalApp::implementation
|
||||
try
|
||||
{
|
||||
_SetFocusedTab(tab);
|
||||
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
|
||||
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, tab));
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -404,7 +378,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// GH#11356 - we can't use the UWP apis for writing the file,
|
||||
// because they don't work elevated (shocker) So just use the
|
||||
// shell32 file picker manually.
|
||||
path = co_await SaveFilePicker(*_hostingHwnd, [control](auto&& dialog) {
|
||||
std::wstring filename{ tab.Title() };
|
||||
path = co_await SaveFilePicker(*_hostingHwnd, [filename = std::move(filename)](auto&& dialog) mutable {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExportFile));
|
||||
try
|
||||
{
|
||||
@@ -418,7 +393,8 @@ namespace winrt::TerminalApp::implementation
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"txt"));
|
||||
|
||||
// Default to using the tab title as the file name
|
||||
THROW_IF_FAILED(dialog->SetFileName((control.Title() + L".txt").c_str()));
|
||||
filename = til::clean_filename(filename);
|
||||
THROW_IF_FAILED(dialog->SetFileName((filename + L".txt").c_str()));
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
FontSize="12">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip Placement="Mouse">
|
||||
<TextBlock IsTextSelectionEnabled="False">
|
||||
<TextBlock IsTextSelectionEnabled="False"
|
||||
TextWrapping="Wrap">
|
||||
<Run x:Uid="NewTabRun" /> <LineBreak />
|
||||
<Run x:Uid="NewPaneRun"
|
||||
FontStyle="Italic" /> <LineBreak />
|
||||
|
||||
@@ -20,17 +20,11 @@
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- HERE BE DRAGONS:
|
||||
@@ -407,13 +401,6 @@
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<!--
|
||||
By default, the PRI file will contain resource paths beginning with the
|
||||
project name. Since we enabled XBF embedding, this *also* includes App.xbf.
|
||||
|
||||
@@ -511,7 +511,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"NewTabByDragDrop",
|
||||
TraceLoggingDescription("Event emitted when the user drag&drops onto the new tab button"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1178,7 +1178,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The profile's GUID"),
|
||||
TraceLoggingGuid(sessionGuid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return connection;
|
||||
}
|
||||
@@ -1326,6 +1326,29 @@ namespace winrt::TerminalApp::implementation
|
||||
e.Handled(true);
|
||||
}
|
||||
|
||||
bool TerminalPage::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
|
||||
{
|
||||
const auto modifiers = _GetPressedModifierKeys();
|
||||
if (vkey == VK_SPACE && modifiers.IsAltPressed() && down)
|
||||
{
|
||||
if (const auto actionMap = _settings.ActionMap())
|
||||
{
|
||||
if (const auto cmd = actionMap.GetActionByKeyChord({
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
modifiers.IsWinPressed(),
|
||||
gsl::narrow_cast<int32_t>(vkey),
|
||||
scanCode,
|
||||
}))
|
||||
{
|
||||
return _actionDispatch->DoAction(cmd.ActionAndArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the modifier keys that are currently pressed. This can be used to
|
||||
// find out which modifiers (ctrl, alt, shift) are pressed in events that
|
||||
@@ -1531,6 +1554,20 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
hostingTab.ColorPickerRequested([weakTab, weakThis]() {
|
||||
auto page{ weakThis.get() };
|
||||
auto tab{ weakTab.get() };
|
||||
if (page && tab)
|
||||
{
|
||||
if (!page->_tabColorPicker)
|
||||
{
|
||||
page->_tabColorPicker = winrt::make<ColorPickupFlyout>();
|
||||
}
|
||||
|
||||
tab->AttachColorPicker(page->_tabColorPicker);
|
||||
}
|
||||
});
|
||||
|
||||
// Add an event handler for when the terminal or tab wants to set a
|
||||
// progress indicator on the taskbar
|
||||
hostingTab.TaskbarProgressChanged({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
|
||||
@@ -2500,8 +2537,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// - newTerminalArgs: an object that may contain a blob of parameters to
|
||||
// control which profile is created and with possible other
|
||||
// configurations. See CascadiaSettings::BuildSettings for more details.
|
||||
// - duplicate: a boolean to indicate whether the pane we create should be
|
||||
// a duplicate of the currently focused pane
|
||||
// - sourceTab: an optional tab reference that indicates that the created
|
||||
// pane should be a duplicate of the tab's focused pane
|
||||
// - existingConnection: optionally receives a connection from the outside
|
||||
// world instead of attempting to create one
|
||||
// Return Value:
|
||||
@@ -2509,29 +2546,25 @@ namespace winrt::TerminalApp::implementation
|
||||
// connection, then we'll return nullptr. Otherwise, we'll return a new
|
||||
// Pane for this connection.
|
||||
std::shared_ptr<Pane> TerminalPage::_MakePane(const NewTerminalArgs& newTerminalArgs,
|
||||
const bool duplicate,
|
||||
const winrt::TerminalApp::TabBase& sourceTab,
|
||||
TerminalConnection::ITerminalConnection existingConnection)
|
||||
{
|
||||
TerminalSettingsCreateResult controlSettings{ nullptr };
|
||||
Profile profile{ nullptr };
|
||||
|
||||
if (duplicate)
|
||||
if (const auto& terminalTab{ _GetTerminalTabImpl(sourceTab) })
|
||||
{
|
||||
const auto focusedTab{ _GetFocusedTabImpl() };
|
||||
if (focusedTab)
|
||||
profile = terminalTab->GetFocusedProfile();
|
||||
if (profile)
|
||||
{
|
||||
profile = focusedTab->GetFocusedProfile();
|
||||
if (profile)
|
||||
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
|
||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
||||
const auto workingDirectory = terminalTab->GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
|
||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
||||
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3264,13 +3297,18 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
newTerminalArgs.Commandline(connection.Commandline());
|
||||
newTerminalArgs.TabTitle(connection.StartingTitle());
|
||||
// GH #12370: We absolutely cannot allow a defterm connection to
|
||||
// auto-elevate. Defterm doesn't work for elevated scenarios in the
|
||||
// first place. If we try accepting the connection, the spawning an
|
||||
// elevated version of the Terminal with that profile... that's a
|
||||
// recipe for disaster. We won't ever open up a tab in this window.
|
||||
newTerminalArgs.Elevate(false);
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, connection));
|
||||
const auto newPane = _MakePane(newTerminalArgs, nullptr, connection);
|
||||
newPane->WalkTree([](auto pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
@@ -3457,7 +3495,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipPresented", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
infoBar.IsOpen(true);
|
||||
}
|
||||
}
|
||||
@@ -3482,7 +3519,7 @@ namespace winrt::TerminalApp::implementation
|
||||
return winrt::hstring{ TabletInputServiceKey };
|
||||
}
|
||||
|
||||
wil::unique_schandle hManager{ OpenSCManager(nullptr, nullptr, 0) };
|
||||
wil::unique_schandle hManager{ OpenSCManagerW(nullptr, nullptr, 0) };
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!hManager.is_valid()))
|
||||
{
|
||||
@@ -3490,15 +3527,24 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
DWORD cchBuffer = 0;
|
||||
GetServiceDisplayName(hManager.get(), TabletInputServiceKey.data(), nullptr, &cchBuffer);
|
||||
const auto ok = GetServiceDisplayNameW(hManager.get(), TabletInputServiceKey.data(), nullptr, &cchBuffer);
|
||||
|
||||
// Windows 11 doesn't have a TabletInputService.
|
||||
// (It was renamed to TextInputManagementService, because people kept thinking that a
|
||||
// service called "tablet-something" is system-irrelevant on PCs and can be disabled.)
|
||||
if (ok || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
return winrt::hstring{ TabletInputServiceKey };
|
||||
}
|
||||
|
||||
std::wstring buffer;
|
||||
cchBuffer += 1; // Add space for a null
|
||||
buffer.resize(cchBuffer);
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!GetServiceDisplayName(hManager.get(),
|
||||
TabletInputServiceKey.data(),
|
||||
buffer.data(),
|
||||
&cchBuffer)))
|
||||
if (LOG_LAST_ERROR_IF(!GetServiceDisplayNameW(hManager.get(),
|
||||
TabletInputServiceKey.data(),
|
||||
buffer.data(),
|
||||
&cchBuffer)))
|
||||
{
|
||||
return winrt::hstring{ TabletInputServiceKey };
|
||||
}
|
||||
|
||||
@@ -135,6 +135,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void OpenSettingsUI();
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
@@ -171,6 +173,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::TabRowControl _tabRow{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
|
||||
Microsoft::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr };
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPicker{ nullptr };
|
||||
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
|
||||
@@ -378,7 +381,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
|
||||
|
||||
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
|
||||
const bool duplicate = false,
|
||||
const winrt::TerminalApp::TabBase& sourceTab = nullptr,
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
|
||||
void _RefreshUIForSettingsReload();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
import "TaskbarState.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
@@ -16,7 +17,7 @@ namespace TerminalApp
|
||||
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener
|
||||
{
|
||||
TerminalPage();
|
||||
|
||||
|
||||
@@ -648,6 +648,46 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attaches the given color picker to ourselves
|
||||
// - Typically will be called after we have sent a request for the color picker
|
||||
// Arguments:
|
||||
// - colorPicker: The color picker that we should attach to ourselves
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::AttachColorPicker(TerminalApp::ColorPickupFlyout& colorPicker)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
_tabColorPickup = colorPicker;
|
||||
|
||||
_colorSelectedToken = _tabColorPickup.ColorSelected([weakThis](auto newTabColor) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->SetRuntimeTabColor(newTabColor);
|
||||
}
|
||||
});
|
||||
|
||||
_colorClearedToken = _tabColorPickup.ColorCleared([weakThis]() {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->ResetRuntimeTabColor();
|
||||
}
|
||||
});
|
||||
|
||||
_pickerClosedToken = _tabColorPickup.Closed([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_tabColorPickup.ColorSelected(tab->_colorSelectedToken);
|
||||
tab->_tabColorPickup.ColorCleared(tab->_colorClearedToken);
|
||||
tab->_tabColorPickup.Closed(tab->_pickerClosedToken);
|
||||
tab->_tabColorPickup = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
_tabColorPickup.ShowAt(TabViewItem());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Find the currently active pane, and then switch the split direction of
|
||||
// its parent. E.g. switch from Horizontal to Vertical.
|
||||
@@ -1184,27 +1224,12 @@ namespace winrt::TerminalApp::implementation
|
||||
chooseColorMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->ActivateColorPicker();
|
||||
tab->RequestColorPicker();
|
||||
}
|
||||
});
|
||||
chooseColorMenuItem.Text(RS_(L"TabColorChoose"));
|
||||
chooseColorMenuItem.Icon(colorPickSymbol);
|
||||
|
||||
// Color Picker (it's convenient to have it here)
|
||||
_tabColorPickup.ColorSelected([weakThis](auto newTabColor) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->SetRuntimeTabColor(newTabColor);
|
||||
}
|
||||
});
|
||||
|
||||
_tabColorPickup.ColorCleared([weakThis]() {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->ResetRuntimeTabColor();
|
||||
}
|
||||
});
|
||||
|
||||
Controls::MenuFlyoutItem renameTabMenuItem;
|
||||
{
|
||||
// "Rename Tab"
|
||||
@@ -1452,18 +1477,16 @@ namespace winrt::TerminalApp::implementation
|
||||
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
|
||||
}
|
||||
|
||||
hoverTabBrush.Color(TerminalApp::ColorHelper::GetAccentColor(color));
|
||||
selectedTabBrush.Color(color);
|
||||
|
||||
// currently if a tab has a custom color, a deselected state is
|
||||
// signified by using the same color with a bit of transparency
|
||||
auto deselectedTabColor = color;
|
||||
deselectedTabColor.A = 64;
|
||||
deselectedTabBrush.Color(deselectedTabColor);
|
||||
deselectedTabBrush.Color(color);
|
||||
deselectedTabBrush.Opacity(0.3);
|
||||
|
||||
hoverTabBrush.Color(color);
|
||||
hoverTabBrush.Opacity(0.6);
|
||||
|
||||
// currently if a tab has a custom color, a deselected state is
|
||||
// signified by using the same color with a bit of transparency
|
||||
//
|
||||
// Prior to MUX 2.7, we set TabViewItemHeaderBackground, but now we can
|
||||
// use TabViewItem().Background() for that. HOWEVER,
|
||||
// TabViewItem().Background() only sets the color of the tab background
|
||||
@@ -1568,14 +1591,15 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Display the tab color picker at the location of the TabViewItem for this tab.
|
||||
// - Send an event to request for the color picker
|
||||
// - The listener should attach the color picker via AttachColorPicker()
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::ActivateColorPicker()
|
||||
void TerminalTab::RequestColorPicker()
|
||||
{
|
||||
_tabColorPickup.ShowAt(TabViewItem());
|
||||
_ColorPickerRequestedHandlers();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<Pane> DetachPane();
|
||||
void AttachPane(std::shared_ptr<Pane> pane);
|
||||
|
||||
void AttachColorPicker(winrt::TerminalApp::ColorPickupFlyout& colorPicker);
|
||||
|
||||
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const float splitSize,
|
||||
std::shared_ptr<Pane> newPane);
|
||||
@@ -73,7 +75,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void SetRuntimeTabColor(const winrt::Windows::UI::Color& color);
|
||||
void ResetRuntimeTabColor();
|
||||
void ActivateColorPicker();
|
||||
void RequestColorPicker();
|
||||
|
||||
void UpdateZoom(std::shared_ptr<Pane> newFocus);
|
||||
void ToggleZoom();
|
||||
@@ -104,6 +106,7 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_CALLBACK(SplitTabRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(FindRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(ExportTabRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(ColorPickerRequested, winrt::delegate<>);
|
||||
TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
@@ -112,12 +115,16 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<Pane> _zoomedPane{ nullptr };
|
||||
|
||||
winrt::hstring _lastIconPath{};
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
|
||||
std::optional<winrt::Windows::UI::Color> _themeTabColor{};
|
||||
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
|
||||
winrt::TerminalApp::TabHeaderControl _headerControl{};
|
||||
winrt::TerminalApp::TerminalTabStatus _tabStatus{};
|
||||
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{ nullptr };
|
||||
winrt::event_token _colorSelectedToken;
|
||||
winrt::event_token _colorClearedToken;
|
||||
winrt::event_token _pickerClosedToken;
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::event_token titleToken;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -92,14 +93,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.2-prerelease.220406002" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3-prerelease.220816001" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -264,13 +264,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
if (_state == AzureState::TermConnected)
|
||||
{
|
||||
// Close the websocket connection
|
||||
auto closedTask = _cloudShellSocket.close();
|
||||
closedTask.wait();
|
||||
_cloudShellSocket.close();
|
||||
}
|
||||
|
||||
if (_hOutputThread)
|
||||
{
|
||||
// Tear down our output thread
|
||||
// Waiting for the output thread to exit ensures that all pending _TerminalOutputHandlers()
|
||||
// calls have returned and won't notify our caller (ControlCore) anymore. This ensures that
|
||||
// we don't call a destroyed event handler asynchronously from a background thread (GH#13880).
|
||||
WaitForSingleObject(_hOutputThread.get(), INFINITE);
|
||||
_hOutputThread.reset();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,12 @@ CATCH_RETURN()
|
||||
HRESULT CTerminalHandoff::s_StopListening()
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
return s_StopListeningLocked();
|
||||
}
|
||||
|
||||
// See s_StopListening()
|
||||
HRESULT CTerminalHandoff::s_StopListeningLocked()
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
_pfnHandoff = nullptr;
|
||||
@@ -97,18 +102,20 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out) noexcept
|
||||
// - E_NOT_VALID_STATE if a event handler is not registered before calling. `::DuplicateHandle`
|
||||
// error codes if we cannot manage to make our own copy of handles to retain. Or S_OK/error
|
||||
// from the registered handler event function.
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Stash a local copy of _pfnHandoff before we stop listening.
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
// s_StopListeningLocked sets _pfnHandoff to nullptr.
|
||||
// localPfnHandoff is tested for nullness below.
|
||||
#pragma warning(suppress : 26429) // Symbol '...' is never tested for nullness, it can be marked as not_null (f.23).
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
s_StopListening();
|
||||
|
||||
std::unique_lock lock{ _mtx };
|
||||
LOG_IF_FAILED(s_StopListeningLocked());
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
@@ -125,7 +132,7 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
|
||||
THROW_IF_FAILED(_duplicateHandle(client, client));
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, ref, server, client));
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, ref, server, client, startupInfo));
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
|
||||
@@ -26,10 +26,10 @@ Author(s):
|
||||
#define __CLSID_CTerminalHandoff "051F34EE-C1FD-4B19-AF75-9BA54648434C"
|
||||
#endif
|
||||
|
||||
using NewHandoffFunction = HRESULT (*)(HANDLE, HANDLE, HANDLE, HANDLE, HANDLE, HANDLE);
|
||||
using NewHandoffFunction = HRESULT (*)(HANDLE, HANDLE, HANDLE, HANDLE, HANDLE, HANDLE, TERMINAL_STARTUP_INFO);
|
||||
|
||||
struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
CTerminalHandoff : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>, ITerminalHandoff>
|
||||
CTerminalHandoff : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>, ITerminalHandoff2>
|
||||
{
|
||||
#pragma region ITerminalHandoff
|
||||
STDMETHODIMP EstablishPtyHandoff(HANDLE in,
|
||||
@@ -37,12 +37,16 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
HANDLE signal,
|
||||
HANDLE ref,
|
||||
HANDLE server,
|
||||
HANDLE client) override;
|
||||
HANDLE client,
|
||||
TERMINAL_STARTUP_INFO startupInfo) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
|
||||
static HRESULT s_StopListening();
|
||||
|
||||
private:
|
||||
static HRESULT s_StopListeningLocked();
|
||||
};
|
||||
|
||||
// Disable warnings from the CoCreatableClass macro as the value it provides for
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TraceLoggingGuid(_guid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -203,7 +203,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const HANDLE hOut,
|
||||
const HANDLE hRef,
|
||||
const HANDLE hServerProcess,
|
||||
const HANDLE hClientProcess) :
|
||||
const HANDLE hClientProcess,
|
||||
TERMINAL_STARTUP_INFO startupInfo) :
|
||||
_initialRows{ 25 },
|
||||
_initialCols{ 80 },
|
||||
_guid{ Utils::CreateGuid() },
|
||||
@@ -213,6 +214,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
THROW_IF_FAILED(ConptyPackPseudoConsole(hServerProcess, hRef, hSig, &_hPC));
|
||||
_piClient.hProcess = hClientProcess;
|
||||
|
||||
_startupInfo.title = winrt::hstring{ startupInfo.pszTitle, SysStringLen(startupInfo.pszTitle) };
|
||||
_startupInfo.iconPath = winrt::hstring{ startupInfo.pszIconPath, SysStringLen(startupInfo.pszIconPath) };
|
||||
_startupInfo.iconIndex = startupInfo.iconIndex;
|
||||
|
||||
try
|
||||
{
|
||||
_commandline = _commandlineFromProcess(hClientProcess);
|
||||
@@ -288,6 +293,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
return _commandline;
|
||||
}
|
||||
|
||||
winrt::hstring ConptyConnection::StartingTitle() const
|
||||
{
|
||||
return _startupInfo.title;
|
||||
}
|
||||
|
||||
void ConptyConnection::Start()
|
||||
try
|
||||
{
|
||||
@@ -336,7 +346,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TraceLoggingGuid(_guid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), til::unwrap_coord_size(dimensions)));
|
||||
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
|
||||
@@ -535,28 +545,34 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
if (_transitionToState(ConnectionState::Closing))
|
||||
{
|
||||
// EXIT POINT
|
||||
_clientExitWait.reset(); // immediately stop waiting for the client to exit.
|
||||
|
||||
// _clientExitWait holds a CreateThreadpoolWait() which holds a weak reference to "this".
|
||||
// This manual reset() ensures we wait for it to be teared down via WaitForThreadpoolWaitCallbacks().
|
||||
_clientExitWait.reset();
|
||||
|
||||
_hPC.reset(); // tear down the pseudoconsole (this is like clicking X on a console window)
|
||||
|
||||
// CloseHandle() on pipes blocks until any current WriteFile()/ReadFile() has returned.
|
||||
// CancelSynchronousIo prevents us from deadlocking ourselves.
|
||||
// At this point in Close(), _inPipe won't be used anymore since the UI parts are torn down.
|
||||
// _outPipe is probably still stuck in ReadFile() and might currently be written to.
|
||||
if (_hOutputThread)
|
||||
{
|
||||
CancelSynchronousIo(_hOutputThread.get());
|
||||
}
|
||||
|
||||
_inPipe.reset(); // break the pipes
|
||||
_outPipe.reset();
|
||||
|
||||
if (_hOutputThread)
|
||||
{
|
||||
// Tear down our output thread -- now that the output pipe was closed on the
|
||||
// far side, we can run down our local reader.
|
||||
// Waiting for the output thread to exit ensures that all pending _TerminalOutputHandlers()
|
||||
// calls have returned and won't notify our caller (ControlCore) anymore. This ensures that
|
||||
// we don't call a destroyed event handler asynchronously from a background thread (GH#13880).
|
||||
LOG_LAST_ERROR_IF(WAIT_FAILED == WaitForSingleObject(_hOutputThread.get(), INFINITE));
|
||||
_hOutputThread.reset();
|
||||
}
|
||||
|
||||
if (_piClient.hProcess)
|
||||
{
|
||||
// Wait for the client to terminate (which it should do successfully)
|
||||
LOG_LAST_ERROR_IF(WAIT_FAILED == WaitForSingleObject(_piClient.hProcess, INFINITE));
|
||||
_piClient.reset();
|
||||
}
|
||||
|
||||
_transitionToState(ConnectionState::Closed);
|
||||
}
|
||||
}
|
||||
@@ -606,10 +622,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
DWORD read{};
|
||||
|
||||
const auto readFail{ !ReadFile(_outPipe.get(), _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), &read, nullptr) };
|
||||
|
||||
// When we call CancelSynchronousIo() in Close() this is the branch that's taken and gets us out of here.
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (readFail) // reading failed (we must check this first, because read will also be 0.)
|
||||
{
|
||||
const auto lastError = GetLastError();
|
||||
if (lastError != ERROR_BROKEN_PIPE && !_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
if (lastError != ERROR_BROKEN_PIPE)
|
||||
{
|
||||
// EXIT POINT
|
||||
_indicateExitWithStatus(HRESULT_FROM_WIN32(lastError)); // print a message
|
||||
@@ -622,12 +645,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
|
||||
if (FAILED(result))
|
||||
{
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
// This termination was expected.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXIT POINT
|
||||
_indicateExitWithStatus(result); // print a message
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
@@ -667,10 +684,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
winrt::event_token ConptyConnection::NewConnection(const NewConnectionHandler& handler) { return _newConnectionHandlers.add(handler); };
|
||||
void ConptyConnection::NewConnection(const winrt::event_token& token) { _newConnectionHandlers.remove(token); };
|
||||
|
||||
HRESULT ConptyConnection::NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept
|
||||
HRESULT ConptyConnection::NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo) noexcept
|
||||
try
|
||||
{
|
||||
_newConnectionHandlers(winrt::make<ConptyConnection>(signal, in, out, ref, server, client));
|
||||
_newConnectionHandlers(winrt::make<ConptyConnection>(signal, in, out, ref, server, client, startupInfo));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
#include <conpty-static.h>
|
||||
|
||||
#include "ITerminalHandoff.h"
|
||||
|
||||
namespace wil
|
||||
{
|
||||
// These belong in WIL upstream, so when we reingest the change that has them we'll get rid of ours.
|
||||
using unique_static_pseudoconsole_handle = wil::unique_any<HPCON, decltype(&::ConptyClosePseudoConsole), ::ConptyClosePseudoConsole>;
|
||||
using unique_static_pseudoconsole_handle = wil::unique_any<HPCON, decltype(&::ConptyClosePseudoConsole), ::ConptyClosePseudoConsoleNoWait>;
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
@@ -23,7 +25,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const HANDLE hOut,
|
||||
const HANDLE hRef,
|
||||
const HANDLE hServerProcess,
|
||||
const HANDLE hClientProcess);
|
||||
const HANDLE hClientProcess,
|
||||
TERMINAL_STARTUP_INFO startupInfo);
|
||||
|
||||
ConptyConnection() noexcept = default;
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& settings);
|
||||
@@ -42,6 +45,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
winrt::guid Guid() const noexcept;
|
||||
winrt::hstring Commandline() const;
|
||||
winrt::hstring StartingTitle() const;
|
||||
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
@@ -60,7 +64,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
|
||||
|
||||
private:
|
||||
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept;
|
||||
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo) noexcept;
|
||||
static winrt::hstring _commandlineFromProcess(HANDLE process);
|
||||
|
||||
HRESULT _LaunchAttachedClient() noexcept;
|
||||
@@ -93,6 +97,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
std::array<char, 4096> _buffer{};
|
||||
bool _passthroughMode{};
|
||||
|
||||
struct StartupInfoFromDefTerm
|
||||
{
|
||||
winrt::hstring title{};
|
||||
winrt::hstring iconPath{};
|
||||
int32_t iconIndex{};
|
||||
|
||||
} _startupInfo{};
|
||||
|
||||
DWORD _OutputThread();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
ConptyConnection();
|
||||
Guid Guid { get; };
|
||||
String Commandline { get; };
|
||||
String StartingTitle { get; };
|
||||
|
||||
void ClearBuffer();
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "pch.h"
|
||||
#include "ControlCore.h"
|
||||
|
||||
// MidiAudio
|
||||
#include <mmeapi.h>
|
||||
#include <dsound.h>
|
||||
|
||||
#include <DefaultSettings.h>
|
||||
#include <unicode.hpp>
|
||||
#include <Utf16Parser.hpp>
|
||||
@@ -89,7 +93,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_settings = winrt::make_self<implementation::ControlSettings>(settings, unfocusedAppearance);
|
||||
|
||||
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
|
||||
_terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>();
|
||||
|
||||
// Subscribe to the connection's disconnected event and call our connection closed handlers.
|
||||
_connectionStateChangedRevoker = _connection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) {
|
||||
@@ -195,13 +199,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
_updatePatternLocations = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
_dispatcher,
|
||||
// NOTE: Calling UpdatePatternLocations from a background
|
||||
// thread is a workaround for us to hit GH#12607 less often.
|
||||
_updatePatternLocations = std::make_unique<til::throttled_func_trailing<>>(
|
||||
UpdatePatternLocationsInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto core{ weakThis.get() }; !core->_IsClosing())
|
||||
[weakTerminal = std::weak_ptr{ _terminal }]() {
|
||||
if (const auto t = weakTerminal.lock())
|
||||
{
|
||||
core->UpdatePatternLocations();
|
||||
auto lock = t->LockForWriting();
|
||||
t->UpdatePatternsUnderLock();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -226,8 +232,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
_renderer->TriggerTeardown();
|
||||
}
|
||||
|
||||
_shutdownMidiAudio();
|
||||
}
|
||||
|
||||
bool ControlCore::Initialize(const double actualWidth,
|
||||
@@ -386,9 +390,82 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const WORD scanCode,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers)
|
||||
{
|
||||
if (ch == L'\x3') // Ctrl+C or Ctrl+Break
|
||||
{
|
||||
_handleControlC();
|
||||
}
|
||||
|
||||
return _terminal->SendCharEvent(ch, scanCode, modifiers);
|
||||
}
|
||||
|
||||
void ControlCore::_handleControlC()
|
||||
{
|
||||
if (!_midiAudioSkipTimer)
|
||||
{
|
||||
_midiAudioSkipTimer = _dispatcher.CreateTimer();
|
||||
_midiAudioSkipTimer.Interval(std::chrono::seconds(1));
|
||||
_midiAudioSkipTimer.IsRepeating(false);
|
||||
_midiAudioSkipTimer.Tick([weakSelf = get_weak()](auto&&, auto&&) {
|
||||
if (const auto self = weakSelf.get())
|
||||
{
|
||||
self->_midiAudio.EndSkip();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_midiAudio.BeginSkip();
|
||||
_midiAudioSkipTimer.Start();
|
||||
}
|
||||
|
||||
bool ControlCore::_shouldTryUpdateSelection(const WORD vkey)
|
||||
{
|
||||
// GH#6423 - don't update selection if the key that was pressed was a
|
||||
// modifier key. We'll wait for a real keystroke to dismiss the
|
||||
// GH #7395 - don't update selection when taking PrintScreen
|
||||
// selection.
|
||||
return HasSelection() && !KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT;
|
||||
}
|
||||
|
||||
bool ControlCore::TryMarkModeKeybinding(const WORD vkey,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates mods)
|
||||
{
|
||||
if (_shouldTryUpdateSelection(vkey) && _terminal->SelectionMode() == ::Terminal::SelectionInteractionMode::Mark)
|
||||
{
|
||||
if (vkey == 'A' && !mods.IsAltPressed() && !mods.IsShiftPressed() && mods.IsCtrlPressed())
|
||||
{
|
||||
// Ctrl + A --> Select all
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SelectAll();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
else if (vkey == VK_RETURN && !mods.IsCtrlPressed() && !mods.IsAltPressed())
|
||||
{
|
||||
// [Shift +] Enter --> copy text
|
||||
// Don't lock here! CopySelectionToClipboard already locks for you!
|
||||
CopySelectionToClipboard(mods.IsShiftPressed(), nullptr);
|
||||
_terminal->ClearSelection();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
else if (vkey == VK_ESCAPE)
|
||||
{
|
||||
_terminal->ClearSelection();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
else if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(mods, vkey) })
|
||||
{
|
||||
// try to update the selection
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, mods);
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Send this particular key event to the terminal.
|
||||
// See Terminal::SendKeyEvent for more information.
|
||||
@@ -405,27 +482,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const bool keyDown)
|
||||
{
|
||||
// Update the selection, if it's present
|
||||
// GH#6423 - don't dismiss selection if the key that was pressed was a
|
||||
// modifier key. We'll wait for a real keystroke to dismiss the
|
||||
// GH #7395 - don't dismiss selection when taking PrintScreen
|
||||
// selection.
|
||||
// GH#8522, GH#3758 - Only modify the selection on key _down_. If we
|
||||
// modify on key up, then there's chance that we'll immediately dismiss
|
||||
// a selection created by an action bound to a keydown.
|
||||
if (HasSelection() &&
|
||||
!KeyEvent::IsModifierKey(vkey) &&
|
||||
vkey != VK_SNAPSHOT &&
|
||||
keyDown)
|
||||
if (_shouldTryUpdateSelection(vkey) && keyDown)
|
||||
{
|
||||
const auto isInMarkMode = _terminal->SelectionMode() == ::Microsoft::Terminal::Core::Terminal::SelectionInteractionMode::Mark;
|
||||
if (isInMarkMode && modifiers.IsCtrlPressed() && vkey == 'A')
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SelectAll();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to update the selection
|
||||
if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) })
|
||||
{
|
||||
@@ -479,7 +540,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// itself - it was initiated by the mouse wheel, or the scrollbar.
|
||||
_terminal->UserScrollViewport(viewTop);
|
||||
|
||||
_updatePatternLocations->Run();
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
|
||||
void ControlCore::AdjustOpacity(const double adjustment)
|
||||
@@ -504,18 +565,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
// Update our runtime opacity value
|
||||
Opacity(newOpacity);
|
||||
_runtimeOpacity = newOpacity;
|
||||
|
||||
// GH#11285 - If the user is on Windows 10, and they changed the
|
||||
// transparency of the control s.t. it should be partially opaque, then
|
||||
// opt them in to acrylic. It's the only way to have transparency on
|
||||
// Windows 10.
|
||||
// We'll also turn the acrylic back off when they're fully opaque, which
|
||||
// is what the Terminal did prior to 1.12.
|
||||
if (!IsVintageOpacityAvailable())
|
||||
{
|
||||
_runtimeUseAcrylic = newOpacity < 1.0;
|
||||
}
|
||||
// Manually turn off acrylic if they turn off transparency.
|
||||
_runtimeUseAcrylic = newOpacity < 1.0 && _settings->UseAcrylic();
|
||||
|
||||
// Update the renderer as well. It might need to fall back from
|
||||
// cleartype -> grayscale if the BG is transparent / acrylic.
|
||||
@@ -555,16 +608,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tell TerminalCore to update its knowledge about the locations of visible regex patterns
|
||||
// - We should call this (through the throttled function) when something causes the visible
|
||||
// region to change, such as when new text enters the buffer or the viewport is scrolled
|
||||
void ControlCore::UpdatePatternLocations()
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdatePatternsUnderLock();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Updates last hovered cell, renders / removes rendering of hyper-link if required
|
||||
// Arguments:
|
||||
@@ -634,7 +677,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
|
||||
if (_lastHoveredCell.has_value())
|
||||
{
|
||||
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
|
||||
auto uri{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
|
||||
uri.resize(std::min<size_t>(1024u, uri.size())); // Truncate for display
|
||||
return winrt::hstring{ uri };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -654,15 +699,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto lock = _terminal->LockForWriting();
|
||||
|
||||
_runtimeOpacity = std::nullopt;
|
||||
_runtimeUseAcrylic = std::nullopt;
|
||||
|
||||
// GH#11285 - If the user is on Windows 10, and they wanted opacity, but
|
||||
// didn't explicitly request acrylic, then opt them in to acrylic.
|
||||
// On Windows 11+, this isn't needed, because we can have vintage opacity.
|
||||
if (!IsVintageOpacityAvailable() && _settings->Opacity() < 1.0 && !_settings->UseAcrylic())
|
||||
{
|
||||
_runtimeUseAcrylic = true;
|
||||
}
|
||||
// Manually turn off acrylic if they turn off transparency.
|
||||
_runtimeUseAcrylic = _settings->Opacity() < 1.0 && _settings->UseAcrylic();
|
||||
|
||||
const auto sizeChanged = _setFontSizeUnderLock(_settings->FontSize());
|
||||
|
||||
@@ -860,6 +899,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void ControlCore::_refreshSizeUnderLock()
|
||||
{
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto cx = gsl::narrow_cast<til::CoordType>(_panelWidth * _compositionScale);
|
||||
auto cy = gsl::narrow_cast<til::CoordType>(_panelHeight * _compositionScale);
|
||||
|
||||
@@ -1094,6 +1138,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (_terminal->IsSelectionActive())
|
||||
{
|
||||
_terminal->SwitchSelectionEndpoint();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1280,7 +1325,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
// Additionally, start the throttled update of where our links are.
|
||||
_updatePatternLocations->Run();
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
|
||||
void ControlCore::_terminalCursorPositionChanged()
|
||||
@@ -1312,56 +1357,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - duration - How long the note should be sustained (in microseconds).
|
||||
void ControlCore::_terminalPlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration)
|
||||
{
|
||||
// We create the audio instance on demand, and lock it for the duration
|
||||
// of the note output so it can't be destroyed while in use.
|
||||
auto& midiAudio = _getMidiAudio();
|
||||
midiAudio.Lock();
|
||||
|
||||
// We then unlock the terminal, so the UI doesn't hang while we're busy.
|
||||
// Unlock the terminal, so the UI doesn't hang while we're busy.
|
||||
auto& terminalLock = _terminal->GetReadWriteLock();
|
||||
terminalLock.unlock();
|
||||
|
||||
// This call will block for the duration, unless shutdown early.
|
||||
midiAudio.PlayNote(noteNumber, velocity, duration);
|
||||
_midiAudio.PlayNote(reinterpret_cast<HWND>(_owningHwnd), noteNumber, velocity, std::chrono::duration_cast<std::chrono::milliseconds>(duration));
|
||||
|
||||
// Once complete, we reacquire the terminal lock and unlock the audio.
|
||||
// If the terminal has shutdown in the meantime, the Unlock call
|
||||
// will throw an exception, forcing the thread to exit ASAP.
|
||||
terminalLock.lock();
|
||||
midiAudio.Unlock();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the MIDI audio instance, created on demand.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - a reference to the MidiAudio instance.
|
||||
MidiAudio& ControlCore::_getMidiAudio()
|
||||
{
|
||||
if (!_midiAudio)
|
||||
{
|
||||
_midiAudio = std::make_unique<MidiAudio>();
|
||||
_midiAudio->Initialize();
|
||||
}
|
||||
return *_midiAudio;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Shuts down the MIDI audio system if previously instantiated.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void ControlCore::_shutdownMidiAudio()
|
||||
{
|
||||
if (_midiAudio)
|
||||
{
|
||||
// We lock the terminal here to make sure the shutdown promise is
|
||||
// set before the audio is unlocked in the thread that is playing.
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_midiAudio->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlCore::HasSelection() const
|
||||
@@ -1440,48 +1443,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_FoundMatchHandlers(*this, *foundResults);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Asynchronously close our connection. The Connection will likely wait
|
||||
// until the attached process terminates before Close returns. If that's
|
||||
// the case, we don't want to block the UI thread waiting on that process
|
||||
// handle.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget ControlCore::_asyncCloseConnection()
|
||||
{
|
||||
if (auto localConnection{ std::exchange(_connection, nullptr) })
|
||||
{
|
||||
// Close the connection on the background thread.
|
||||
co_await winrt::resume_background(); // ** DO NOT INTERACT WITH THE CONTROL CORE AFTER THIS LINE **
|
||||
|
||||
// Here, the ControlCore very well might be gone.
|
||||
// _asyncCloseConnection is called on the dtor, so it's entirely
|
||||
// possible that the background thread is resuming after we've been
|
||||
// cleaned up.
|
||||
|
||||
localConnection.Close();
|
||||
// connection is destroyed.
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::Close()
|
||||
{
|
||||
if (!_IsClosing())
|
||||
{
|
||||
_closing = true;
|
||||
|
||||
// Ensure Close() doesn't hang, waiting for MidiAudio to finish playing an hour long song.
|
||||
_midiAudio.BeginSkip();
|
||||
|
||||
// Stop accepting new output and state changes before we disconnect everything.
|
||||
_connection.TerminalOutput(_connectionOutputEventToken);
|
||||
_connectionStateChangedRevoker.revoke();
|
||||
|
||||
// GH#1996 - Close the connection asynchronously on a background
|
||||
// thread.
|
||||
// Since TermControl::Close is only ever triggered by the UI, we
|
||||
// don't really care to wait for the connection to be completely
|
||||
// closed. We can just do it whenever.
|
||||
_asyncCloseConnection();
|
||||
_connection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1569,7 +1543,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
auto lock = _terminal->LockForReading();
|
||||
return _terminal->GetCursorPosition().to_core_point();
|
||||
return _terminal->GetViewportRelativeCursorPosition().to_core_point();
|
||||
}
|
||||
|
||||
// This one's really pushing the boundary of what counts as "encapsulation".
|
||||
@@ -1673,7 +1647,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_terminal->Write(hstr);
|
||||
|
||||
// Start the throttled update of where our hyperlinks are.
|
||||
_updatePatternLocations->Run();
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -1741,22 +1715,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return hstring(ss.str());
|
||||
}
|
||||
|
||||
// Helper to check if we're on Windows 11 or not. This is used to check if
|
||||
// we need to use acrylic to achieve transparency, because vintage opacity
|
||||
// doesn't work in islands on win10.
|
||||
// Remove when we can remove the rest of GH#11285
|
||||
bool ControlCore::IsVintageOpacityAvailable() noexcept
|
||||
{
|
||||
OSVERSIONINFOEXW osver{};
|
||||
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||
osver.dwBuildNumber = 22000;
|
||||
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
|
||||
|
||||
return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
|
||||
}
|
||||
|
||||
Core::Scheme ControlCore::ColorScheme() const noexcept
|
||||
{
|
||||
Core::Scheme s;
|
||||
@@ -1911,26 +1869,36 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - This is related to work done for GH#2988.
|
||||
void ControlCore::GotFocus()
|
||||
{
|
||||
_terminal->FocusChanged(true);
|
||||
_focusChanged(true);
|
||||
}
|
||||
|
||||
// See GotFocus.
|
||||
void ControlCore::LostFocus()
|
||||
{
|
||||
_terminal->FocusChanged(false);
|
||||
_focusChanged(false);
|
||||
}
|
||||
|
||||
void ControlCore::_focusChanged(bool focused)
|
||||
{
|
||||
// GH#13461 - temporarily turn off read-only mode, send the focus event,
|
||||
// then turn it back on. Even in focus mode, focus events are fine to
|
||||
// send. We don't want to pop a warning every time the control is
|
||||
// focused.
|
||||
const auto previous = std::exchange(_isReadOnly, false);
|
||||
const auto restore = wil::scope_exit([&]() { _isReadOnly = previous; });
|
||||
_terminal->FocusChanged(focused);
|
||||
}
|
||||
|
||||
bool ControlCore::_isBackgroundTransparent()
|
||||
{
|
||||
// If we're:
|
||||
// * Not fully opaque
|
||||
// * On an acrylic background (of any opacity)
|
||||
// * rendering on top of an image
|
||||
//
|
||||
// then the renderer should not render "default background" text with a
|
||||
// fully opaque background. Doing that would cover up our nice
|
||||
// transparency, or our acrylic, or our image.
|
||||
return Opacity() < 1.0f || UseAcrylic() || !_settings->BackgroundImage().empty() || _settings->UseBackgroundImageForWindow();
|
||||
return Opacity() < 1.0f || !_settings->BackgroundImage().empty() || _settings->UseBackgroundImageForWindow();
|
||||
}
|
||||
|
||||
uint64_t ControlCore::OwningHwnd()
|
||||
|
||||
@@ -87,6 +87,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ToggleMarkMode();
|
||||
Control::SelectionInteractionMode SelectionMode() const;
|
||||
bool SwitchSelectionEndpoint();
|
||||
bool TryMarkModeKeybinding(const WORD vkey,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
|
||||
|
||||
void GotFocus();
|
||||
void LostFocus();
|
||||
@@ -95,7 +97,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void AdjustOpacity(const double adjustment);
|
||||
void ResumeRendering();
|
||||
|
||||
void UpdatePatternLocations();
|
||||
void SetHoveredCell(Core::Point terminalPosition);
|
||||
void ClearHoveredCell();
|
||||
winrt::hstring GetHyperlink(const Core::Point position) const;
|
||||
@@ -230,7 +231,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::com_ptr<ControlSettings> _settings{ nullptr };
|
||||
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||
|
||||
// NOTE: _renderEngine must be ordered before _renderer.
|
||||
//
|
||||
@@ -265,16 +266,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
|
||||
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
|
||||
winrt::fire_and_forget _asyncCloseConnection();
|
||||
|
||||
bool _setFontSizeUnderLock(int fontSize);
|
||||
void _updateFont(const bool initialUpdate = false);
|
||||
void _refreshSizeUnderLock();
|
||||
void _updateSelectionUI();
|
||||
bool _shouldTryUpdateSelection(const WORD vkey);
|
||||
|
||||
void _handleControlC();
|
||||
void _sendInputToConnection(std::wstring_view wstr);
|
||||
|
||||
#pragma region TerminalCoreCallbacks
|
||||
@@ -292,10 +293,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const std::chrono::microseconds duration);
|
||||
#pragma endregion
|
||||
|
||||
std::unique_ptr<MidiAudio> _midiAudio;
|
||||
|
||||
MidiAudio& _getMidiAudio();
|
||||
void _shutdownMidiAudio();
|
||||
MidiAudio _midiAudio;
|
||||
winrt::Windows::System::DispatcherQueueTimer _midiAudioSkipTimer{ nullptr };
|
||||
|
||||
#pragma region RendererCallbacks
|
||||
void _rendererWarning(const HRESULT hr);
|
||||
@@ -311,6 +310,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _setOpacity(const double opacity);
|
||||
|
||||
bool _isBackgroundTransparent();
|
||||
void _focusChanged(bool focused);
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
|
||||
@@ -14,9 +14,7 @@ namespace Microsoft.Terminal.Control
|
||||
// !! LOAD BEARING !! If you make this a struct with Booleans (like they
|
||||
// make the most sense as), then the app will crash trying to toss one of
|
||||
// these across the process boundary. I haven't the damndest idea why.
|
||||
[flags]
|
||||
enum MouseButtonState
|
||||
{
|
||||
[flags] enum MouseButtonState {
|
||||
IsLeftButtonDown = 0x1,
|
||||
IsMiddleButtonDown = 0x2,
|
||||
IsRightButtonDown = 0x4
|
||||
@@ -37,9 +35,7 @@ namespace Microsoft.Terminal.Control
|
||||
Mark
|
||||
};
|
||||
|
||||
[flags]
|
||||
enum SelectionEndpointTarget
|
||||
{
|
||||
[flags] enum SelectionEndpointTarget {
|
||||
Start = 0x1,
|
||||
End = 0x2
|
||||
};
|
||||
@@ -79,13 +75,15 @@ namespace Microsoft.Terminal.Control
|
||||
Double Opacity { get; };
|
||||
Boolean UseAcrylic { get; };
|
||||
|
||||
Boolean TryMarkModeKeybinding(Int16 vkey,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
Boolean TrySendKeyEvent(Int16 vkey,
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean keyDown);
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean keyDown);
|
||||
Boolean SendCharEvent(Char ch,
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
void SendInput(String text);
|
||||
void PasteText(String text);
|
||||
void SelectAll();
|
||||
@@ -109,7 +107,6 @@ namespace Microsoft.Terminal.Control
|
||||
Microsoft.Terminal.Core.Point CursorPosition { get; };
|
||||
void ResumeRendering();
|
||||
void BlinkAttributeTick();
|
||||
void UpdatePatternLocations();
|
||||
void Search(String text, Boolean goForward, Boolean caseSensitive);
|
||||
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "TSFInputControl.h"
|
||||
#include "TSFInputControl.g.cpp"
|
||||
|
||||
#include <Utils.h>
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Graphics::Display;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
@@ -16,17 +14,7 @@ using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TSFInputControl::TSFInputControl() :
|
||||
_editContext{ nullptr },
|
||||
_inComposition{ false },
|
||||
_activeTextStart{ 0 },
|
||||
_focused{ false },
|
||||
_currentTerminalCursorPos{ 0, 0 },
|
||||
_currentCanvasWidth{ 0.0 },
|
||||
_currentTextBlockHeight{ 0.0 },
|
||||
_currentTextBounds{ 0, 0, 0, 0 },
|
||||
_currentControlBounds{ 0, 0, 0, 0 },
|
||||
_currentWindowBounds{ 0, 0, 0, 0 }
|
||||
TSFInputControl::TSFInputControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@@ -83,11 +71,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::NotifyFocusEnter()
|
||||
{
|
||||
if (_editContext != nullptr)
|
||||
{
|
||||
_editContext.NotifyFocusEnter();
|
||||
_focused = true;
|
||||
}
|
||||
_editContext.NotifyFocusEnter();
|
||||
_focused = true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -99,11 +84,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::NotifyFocusLeave()
|
||||
{
|
||||
if (_editContext != nullptr)
|
||||
{
|
||||
_editContext.NotifyFocusLeave();
|
||||
_focused = false;
|
||||
}
|
||||
_editContext.NotifyFocusLeave();
|
||||
_focused = false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -117,14 +99,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (!_inputBuffer.empty())
|
||||
{
|
||||
TextBlock().Text(L"");
|
||||
const auto bufLen = ::base::ClampedNumeric<int32_t>(_inputBuffer.length());
|
||||
_inputBuffer.clear();
|
||||
_editContext.NotifyFocusLeave();
|
||||
_editContext.NotifyTextChanged({ 0, bufLen }, 0, { 0, 0 });
|
||||
_editContext.NotifyFocusEnter();
|
||||
_selection = {};
|
||||
_activeTextStart = 0;
|
||||
_inComposition = false;
|
||||
_editContext.NotifyTextChanged({ 0, INT32_MAX }, 0, _selection);
|
||||
TextBlock().Text({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,12 +282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TSFInputControl::_compositionCompletedHandler(CoreTextEditContext sender, const CoreTextCompositionCompletedEventArgs& /*args*/)
|
||||
{
|
||||
_inComposition = false;
|
||||
|
||||
// only need to do work if the current buffer has text
|
||||
if (!_inputBuffer.empty())
|
||||
{
|
||||
_SendAndClearText();
|
||||
}
|
||||
_SendAndClearText();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -336,16 +310,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::_textRequestedHandler(CoreTextEditContext sender, const CoreTextTextRequestedEventArgs& args)
|
||||
{
|
||||
// the range the TSF wants to know about
|
||||
const auto range = args.Request().Range();
|
||||
|
||||
try
|
||||
{
|
||||
const auto textEnd = ::base::ClampMin<size_t>(range.EndCaretPosition, _inputBuffer.length());
|
||||
const auto length = ::base::ClampSub<size_t>(textEnd, range.StartCaretPosition);
|
||||
const auto textRequested = _inputBuffer.substr(range.StartCaretPosition, length);
|
||||
|
||||
args.Request().Text(textRequested);
|
||||
const auto range = args.Request().Range();
|
||||
const auto text = _inputBuffer.substr(
|
||||
range.StartCaretPosition,
|
||||
range.EndCaretPosition - range.StartCaretPosition);
|
||||
args.Request().Text(text);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -360,8 +331,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - args: CoreTextSelectionRequestedEventArgs for providing data for the SelectionRequested event. Not used in method.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::_selectionRequestedHandler(CoreTextEditContext sender, const CoreTextSelectionRequestedEventArgs& /*args*/)
|
||||
void TSFInputControl::_selectionRequestedHandler(CoreTextEditContext sender, const CoreTextSelectionRequestedEventArgs& args)
|
||||
{
|
||||
args.Request().Selection(_selection);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -374,8 +346,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - args: CoreTextSelectionUpdatingEventArgs for providing data for the SelectionUpdating event. Not used in method.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::_selectionUpdatingHandler(CoreTextEditContext sender, const CoreTextSelectionUpdatingEventArgs& /*args*/)
|
||||
void TSFInputControl::_selectionUpdatingHandler(CoreTextEditContext sender, const CoreTextSelectionUpdatingEventArgs& args)
|
||||
{
|
||||
_selection = args.Selection();
|
||||
args.Result(CoreTextSelectionUpdatingResult::Succeeded);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -388,24 +362,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::_textUpdatingHandler(CoreTextEditContext sender, const CoreTextTextUpdatingEventArgs& args)
|
||||
{
|
||||
const auto incomingText = args.Text();
|
||||
const auto range = args.Range();
|
||||
|
||||
try
|
||||
{
|
||||
// When a user deletes the last character in their current composition, some machines
|
||||
// will fire a CompositionCompleted before firing a TextUpdating event that deletes the last character.
|
||||
// The TextUpdating will have a lower StartCaretPosition, so in this scenario, _activeTextStart
|
||||
// needs to update to be the StartCaretPosition.
|
||||
// A known issue related to this behavior is that the last character that's deleted from a composition
|
||||
// will get sent to the terminal before we receive the TextUpdate to delete the character.
|
||||
// See GH #5054.
|
||||
_activeTextStart = ::base::ClampMin(_activeTextStart, ::base::ClampedNumeric<size_t>(range.StartCaretPosition));
|
||||
const auto incomingText = args.Text();
|
||||
const auto range = args.Range();
|
||||
|
||||
_inputBuffer = _inputBuffer.replace(
|
||||
range.StartCaretPosition,
|
||||
::base::ClampSub<size_t>(range.EndCaretPosition, range.StartCaretPosition),
|
||||
range.EndCaretPosition - range.StartCaretPosition,
|
||||
incomingText);
|
||||
_selection = args.NewSelection();
|
||||
// GH#5054: Pressing backspace might move the caret before the _activeTextStart.
|
||||
_activeTextStart = std::min(_activeTextStart, _inputBuffer.size());
|
||||
|
||||
// Emojis/Kaomojis/Symbols chosen through the IME without starting composition
|
||||
// will be sent straight through to the terminal.
|
||||
@@ -432,22 +400,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Send the portion of the textBuffer starting at _activeTextStart to the end of the buffer.
|
||||
// Then clear the TextBlock and hide it until the next time text is received.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::_SendAndClearText()
|
||||
{
|
||||
const auto text = _inputBuffer.substr(_activeTextStart);
|
||||
if (text.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_CompositionCompletedHandlers(text);
|
||||
|
||||
_activeTextStart = _inputBuffer.length();
|
||||
_activeTextStart = _inputBuffer.size();
|
||||
|
||||
TextBlock().Text(L"");
|
||||
TextBlock().Text({});
|
||||
|
||||
// After we reset the TextBlock to empty string, we want to make sure
|
||||
// ActualHeight reflects the respective height. It seems that ActualHeight
|
||||
|
||||
@@ -58,6 +58,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _textUpdatingHandler(winrt::Windows::UI::Text::Core::CoreTextEditContext sender, const winrt::Windows::UI::Text::Core::CoreTextTextUpdatingEventArgs& args);
|
||||
void _formatUpdatingHandler(winrt::Windows::UI::Text::Core::CoreTextEditContext sender, const winrt::Windows::UI::Text::Core::CoreTextFormatUpdatingEventArgs& args);
|
||||
|
||||
void _SendAndClearText();
|
||||
void _RedrawCanvas();
|
||||
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::TextRequested_revoker _textRequestedRevoker;
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::SelectionRequested_revoker _selectionRequestedRevoker;
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::FocusRemoved_revoker _focusRemovedRevoker;
|
||||
@@ -68,22 +71,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::CompositionStarted_revoker _compositionStartedRevoker;
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::CompositionCompleted_revoker _compositionCompletedRevoker;
|
||||
|
||||
Windows::UI::Text::Core::CoreTextEditContext _editContext;
|
||||
|
||||
Windows::UI::Text::Core::CoreTextEditContext _editContext{ nullptr };
|
||||
std::wstring _inputBuffer;
|
||||
winrt::Windows::UI::Text::Core::CoreTextRange _selection{};
|
||||
size_t _activeTextStart = 0;
|
||||
bool _inComposition = false;
|
||||
bool _focused = false;
|
||||
|
||||
bool _inComposition;
|
||||
size_t _activeTextStart;
|
||||
void _SendAndClearText();
|
||||
void _RedrawCanvas();
|
||||
bool _focused;
|
||||
|
||||
til::point _currentTerminalCursorPos;
|
||||
double _currentCanvasWidth;
|
||||
double _currentTextBlockHeight;
|
||||
winrt::Windows::Foundation::Rect _currentControlBounds;
|
||||
winrt::Windows::Foundation::Rect _currentTextBounds;
|
||||
winrt::Windows::Foundation::Rect _currentWindowBounds;
|
||||
til::point _currentTerminalCursorPos{};
|
||||
double _currentCanvasWidth = 0.0;
|
||||
double _currentTextBlockHeight = 0.0;
|
||||
winrt::Windows::Foundation::Rect _currentControlBounds{};
|
||||
winrt::Windows::Foundation::Rect _currentTextBounds{};
|
||||
winrt::Windows::Foundation::Rect _currentWindowBounds{};
|
||||
};
|
||||
}
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
|
||||
@@ -432,12 +432,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// achieve the intended effect.
|
||||
ScrollBar().IndicatorMode(Controls::Primitives::ScrollingIndicatorMode::None);
|
||||
ScrollBar().Visibility(Visibility::Collapsed);
|
||||
ScrollMarksGrid().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
else // (default or Visible)
|
||||
{
|
||||
// Default behavior
|
||||
ScrollBar().IndicatorMode(Controls::Primitives::ScrollingIndicatorMode::MouseIndicator);
|
||||
ScrollBar().Visibility(Visibility::Visible);
|
||||
ScrollMarksGrid().Visibility(Visibility::Visible);
|
||||
}
|
||||
|
||||
_interactivity.UpdateSettings();
|
||||
@@ -677,7 +679,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
margins.Top,
|
||||
margins.Right,
|
||||
margins.Bottom };
|
||||
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(this, padding, interactivityAutoPeer);
|
||||
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(get_strong(), padding, interactivityAutoPeer);
|
||||
return _automationPeer;
|
||||
}
|
||||
}
|
||||
@@ -902,6 +904,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
// GH#11479: TSF wants to be notified of any character input via ICoreTextEditContext::NotifyTextChanged().
|
||||
// TSF is built and tested around the idea that you inform it of any text changes that happen
|
||||
// when it doesn't currently compose characters. For instance writing "xin chaof" with the
|
||||
// Vietnamese IME should produce "xin chào". After writing "xin" it'll emit a composition
|
||||
// completion event and we'll write "xin" to the shell. It now has no input focus and won't know
|
||||
// about the whitespace. If you then write "chaof", it'll emit another composition completion
|
||||
// event for "xinchaof" and the resulting output in the shell will finally read "xinxinchaof".
|
||||
// A composition completion event technically doesn't mean that the completed text is now
|
||||
// immutable after all. We could (and probably should) inform TSF of any input changes,
|
||||
// but we technically aren't a text input field. The immediate solution was
|
||||
// to simply force TSF to clear its text whenever we have input focus.
|
||||
TSFInputControl().ClearBuffer();
|
||||
|
||||
_HidePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
const auto ch = e.Character();
|
||||
@@ -1066,7 +1081,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// keybindings on the keyUp, then we'll still send the keydown to the
|
||||
// connected terminal application, and something like ctrl+shift+T will
|
||||
// emit a ^T to the pipe.
|
||||
if (!modifiers.IsAltGrPressed() && keyDown && _TryHandleKeyBinding(vkey, scanCode, modifiers))
|
||||
if (!modifiers.IsAltGrPressed() &&
|
||||
keyDown &&
|
||||
_TryHandleKeyBinding(vkey, scanCode, modifiers))
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
@@ -1092,6 +1109,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - modifiers: The ControlKeyStates representing the modifier key states.
|
||||
bool TermControl::_TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const
|
||||
{
|
||||
// Mark mode has a specific set of pre-defined key bindings.
|
||||
// If we're in mark mode, we should be prioritizing those over
|
||||
// the custom defined key bindings.
|
||||
if (_core.TryMarkModeKeybinding(vkey, modifiers))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: GH#5000
|
||||
// The Core owning the keybindings is weird. That's for sure. In the
|
||||
// future, we may want to pass the keybindings into the control
|
||||
@@ -1163,12 +1188,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
const auto window = CoreWindow::GetForCurrentThread();
|
||||
|
||||
if (vkey == VK_ESCAPE ||
|
||||
vkey == VK_RETURN)
|
||||
{
|
||||
TSFInputControl().ClearBuffer();
|
||||
}
|
||||
|
||||
// If the terminal translated the key, mark the event as handled.
|
||||
// This will prevent the system from trying to get the character out
|
||||
// of it and sending us a CharacterReceived event.
|
||||
|
||||
@@ -67,10 +67,10 @@ static constexpr bool IsReadable(std::wstring_view text)
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TermControlAutomationPeer::TermControlAutomationPeer(TermControl* owner,
|
||||
TermControlAutomationPeer::TermControlAutomationPeer(winrt::com_ptr<TermControl> owner,
|
||||
const Core::Padding padding,
|
||||
Control::InteractivityAutomationPeer impl) :
|
||||
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner), // pass owner to FrameworkElementAutomationPeer
|
||||
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner.get()), // pass owner to FrameworkElementAutomationPeer
|
||||
_termControl{ owner },
|
||||
_contentAutomationPeer{ impl }
|
||||
{
|
||||
@@ -134,8 +134,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when the text selection is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
// The event that is raised when the text selection is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -157,8 +160,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when textual content is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
// The event that is raised when textual content is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -180,13 +186,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -236,14 +245,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }, sanitizedCopy{ hstring{ sanitized } }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
try
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
strongThis->RaiseNotificationEvent(AutomationNotificationKind::ActionCompleted,
|
||||
AutomationNotificationProcessing::All,
|
||||
sanitizedCopy,
|
||||
L"TerminalTextOutput");
|
||||
try
|
||||
{
|
||||
strongThis->RaiseNotificationEvent(AutomationNotificationKind::ActionCompleted,
|
||||
AutomationNotificationProcessing::All,
|
||||
sanitizedCopy,
|
||||
L"TerminalTextOutput");
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -284,17 +296,29 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
hstring TermControlAutomationPeer::GetNameCore() const
|
||||
{
|
||||
// fallback to title if profile name is empty
|
||||
auto profileName = _termControl->GetProfileName();
|
||||
if (profileName.empty())
|
||||
if (auto control{ _termControl.get() })
|
||||
{
|
||||
return _termControl->Title();
|
||||
const auto profileName = control->GetProfileName();
|
||||
if (profileName.empty())
|
||||
{
|
||||
return control->Title();
|
||||
}
|
||||
else
|
||||
{
|
||||
return profileName;
|
||||
}
|
||||
}
|
||||
return profileName;
|
||||
|
||||
return L"";
|
||||
}
|
||||
|
||||
hstring TermControlAutomationPeer::GetHelpTextCore() const
|
||||
{
|
||||
return _termControl->Title();
|
||||
if (const auto control{ _termControl.get() })
|
||||
{
|
||||
return control->Title();
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
AutomationLiveSetting TermControlAutomationPeer::GetLiveSettingCore() const
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
::Microsoft::Console::Types::IUiaEventDispatcher
|
||||
{
|
||||
public:
|
||||
TermControlAutomationPeer(Microsoft::Terminal::Control::implementation::TermControl* owner,
|
||||
TermControlAutomationPeer(winrt::com_ptr<Microsoft::Terminal::Control::implementation::TermControl> owner,
|
||||
const Core::Padding padding,
|
||||
Control::InteractivityAutomationPeer implementation);
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
winrt::Microsoft::Terminal::Control::implementation::TermControl* _termControl;
|
||||
winrt::weak_ref<Microsoft::Terminal::Control::implementation::TermControl> _termControl;
|
||||
Control::InteractivityAutomationPeer _contentAutomationPeer;
|
||||
std::deque<wchar_t> _keyEvents;
|
||||
};
|
||||
|
||||
@@ -147,10 +147,6 @@
|
||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
||||
<OCResourceDirectory Include="Resources" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(WindowsTerminalBranding)'=='' or '$(WindowsTerminalBranding)'=='Dev' or '$(WindowsTerminalBranding)'=='Preview'">
|
||||
<!-- GH#13252 Only vend this dependency for Dev and Preview builds. -->
|
||||
<SDKReference Include="Microsoft.Midi.GmDls, Version=10.0.22000.0" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\types\lib\types.vcxproj" />
|
||||
|
||||
@@ -36,23 +36,7 @@ static std::wstring _KeyEventsToText(std::deque<std::unique_ptr<IInputEvent>>& i
|
||||
}
|
||||
|
||||
#pragma warning(suppress : 26455) // default constructor is throwing, too much effort to rearrange at this time.
|
||||
Terminal::Terminal() :
|
||||
_mutableViewport{ Viewport::Empty() },
|
||||
_title{},
|
||||
_pfnWriteInput{ nullptr },
|
||||
_altBuffer{ nullptr },
|
||||
_scrollOffset{ 0 },
|
||||
_snapOnInput{ true },
|
||||
_altGrAliasing{ true },
|
||||
_blockSelection{ false },
|
||||
_selectionMode{ SelectionInteractionMode::None },
|
||||
_selection{ std::nullopt },
|
||||
_selectionEndpoint{ static_cast<SelectionEndpoint>(0) },
|
||||
_anchorInactiveSelectionEndpoint{ false },
|
||||
_taskbarState{ 0 },
|
||||
_taskbarProgress{ 0 },
|
||||
_trimBlockSelection{ false },
|
||||
_autoMarkPrompts{ false }
|
||||
Terminal::Terminal()
|
||||
{
|
||||
auto passAlongInput = [&](std::deque<std::unique_ptr<IInputEvent>>& inEventsToWrite) {
|
||||
if (!_pfnWriteInput)
|
||||
@@ -89,7 +73,7 @@ void Terminal::Create(til::size viewportSize, til::CoordType scrollbackLines, Re
|
||||
// But if they are being accepted by conhost, there's a chance they may get
|
||||
// passed through in some situations, so it's important that our state
|
||||
// machine is always prepared to accept them.
|
||||
_stateMachine->SetParserMode(StateMachine::Mode::AcceptC1, true);
|
||||
_stateMachine->SetParserMode(StateMachine::Mode::AlwaysAcceptC1, true);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1615,3 +1599,12 @@ til::color Terminal::GetColorForMark(const Microsoft::Console::VirtualTerminal::
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the position of the cursor relative to the active viewport
|
||||
til::point Terminal::GetViewportRelativeCursorPosition() const noexcept
|
||||
{
|
||||
const auto absoluteCursorPosition{ GetCursorPosition() };
|
||||
const auto viewport{ _GetMutableViewport() };
|
||||
return absoluteCursorPosition - viewport.Origin();
|
||||
}
|
||||
|
||||
@@ -63,11 +63,6 @@ class Microsoft::Terminal::Core::Terminal final :
|
||||
|
||||
public:
|
||||
Terminal();
|
||||
~Terminal(){};
|
||||
Terminal(const Terminal&) = default;
|
||||
Terminal(Terminal&&) = default;
|
||||
Terminal& operator=(const Terminal&) = default;
|
||||
Terminal& operator=(Terminal&&) = default;
|
||||
|
||||
void Create(til::size viewportSize,
|
||||
til::CoordType scrollbackLines,
|
||||
@@ -84,6 +79,8 @@ public:
|
||||
bool IsXtermBracketedPasteModeEnabled() const;
|
||||
std::wstring_view GetWorkingDirectory();
|
||||
|
||||
til::point GetViewportRelativeCursorPosition() const noexcept;
|
||||
|
||||
// Write comes from the PTY and goes to our parser to be stored in the output buffer
|
||||
void Write(std::wstring_view stringView);
|
||||
|
||||
@@ -260,6 +257,7 @@ public:
|
||||
|
||||
enum class SelectionEndpoint
|
||||
{
|
||||
None = 0,
|
||||
Start = 0x1,
|
||||
End = 0x2
|
||||
};
|
||||
@@ -314,19 +312,19 @@ private:
|
||||
std::wstring _startingTitle;
|
||||
std::optional<til::color> _startingTabColor;
|
||||
|
||||
CursorType _defaultCursorShape;
|
||||
CursorType _defaultCursorShape = CursorType::Legacy;
|
||||
|
||||
bool _snapOnInput;
|
||||
bool _altGrAliasing;
|
||||
bool _suppressApplicationTitle;
|
||||
bool _bracketedPasteMode;
|
||||
bool _trimBlockSelection;
|
||||
bool _autoMarkPrompts;
|
||||
bool _snapOnInput = true;
|
||||
bool _altGrAliasing = true;
|
||||
bool _suppressApplicationTitle = false;
|
||||
bool _bracketedPasteMode = false;
|
||||
bool _trimBlockSelection = false;
|
||||
bool _autoMarkPrompts = false;
|
||||
|
||||
size_t _taskbarState;
|
||||
size_t _taskbarProgress;
|
||||
size_t _taskbarState = 0;
|
||||
size_t _taskbarProgress = 0;
|
||||
|
||||
size_t _hyperlinkPatternId;
|
||||
size_t _hyperlinkPatternId = 0;
|
||||
|
||||
std::wstring _workingDirectory;
|
||||
|
||||
@@ -345,26 +343,26 @@ private:
|
||||
til::point pivot;
|
||||
};
|
||||
std::optional<SelectionAnchors> _selection;
|
||||
bool _blockSelection;
|
||||
bool _blockSelection = false;
|
||||
std::wstring _wordDelimiters;
|
||||
SelectionExpansion _multiClickSelectionMode;
|
||||
SelectionInteractionMode _selectionMode;
|
||||
SelectionEndpoint _selectionEndpoint;
|
||||
bool _anchorInactiveSelectionEndpoint;
|
||||
SelectionExpansion _multiClickSelectionMode = SelectionExpansion::Char;
|
||||
SelectionInteractionMode _selectionMode = SelectionInteractionMode::None;
|
||||
SelectionEndpoint _selectionEndpoint = SelectionEndpoint::None;
|
||||
bool _anchorInactiveSelectionEndpoint = false;
|
||||
#pragma endregion
|
||||
|
||||
std::unique_ptr<TextBuffer> _mainBuffer;
|
||||
std::unique_ptr<TextBuffer> _altBuffer;
|
||||
Microsoft::Console::Types::Viewport _mutableViewport;
|
||||
til::CoordType _scrollbackLines;
|
||||
bool _detectURLs{ false };
|
||||
til::CoordType _scrollbackLines = 0;
|
||||
bool _detectURLs = false;
|
||||
|
||||
til::size _altBufferSize;
|
||||
std::optional<til::size> _deferredResize{ std::nullopt };
|
||||
std::optional<til::size> _deferredResize;
|
||||
|
||||
// _scrollOffset is the number of lines above the viewport that are currently visible
|
||||
// If _scrollOffset is 0, then the visible region of the buffer is the viewport.
|
||||
int _scrollOffset;
|
||||
til::CoordType _scrollOffset = 0;
|
||||
// TODO this might not be the value we want to store.
|
||||
// We might want to store the height in the scrollback that's currently visible.
|
||||
// Think on this some more.
|
||||
@@ -424,6 +422,7 @@ private:
|
||||
std::pair<til::point, til::point> _PivotSelection(const til::point targetPos, bool& targetStart) const;
|
||||
std::pair<til::point, til::point> _ExpandSelectionAnchors(std::pair<til::point, til::point> anchors) const;
|
||||
til::point _ConvertToBufferCell(const til::point viewportPos) const;
|
||||
void _ScrollToPoint(const til::point pos);
|
||||
void _MoveByChar(SelectionDirection direction, til::point& pos);
|
||||
void _MoveByWord(SelectionDirection direction, til::point& pos);
|
||||
void _MoveByViewport(SelectionDirection direction, til::point& pos);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user