Compare commits

...

125 Commits

Author SHA1 Message Date
Dustin L. Howett
470d9084d3 Migrate spelling-0.0.21 changes from main 2021-11-16 07:07:01 -06:00
Mike Griese
065e5f7d90 fix unit test build 2021-11-16 07:07:01 -06:00
Mike Griese
841ced7e57 cant type when it's 26 degrees in here 2021-11-16 06:06:42 -06:00
Mike Griese
056446cd3e guard some GetActiveTerminalControl calls 2021-11-16 05:58:06 -06:00
Mike Griese
25947c2f40 cleanup for the tests" 2021-11-16 05:35:47 -06:00
Mike Griese
2445cedb92 this passes all the tests 2021-11-16 05:13:16 -06:00
Mike Griese
8e43c9d8ce more tests 2021-11-15 11:22:41 -06:00
Mike Griese
fd72b7992e Merge remote-tracking branch 'origin/main' into dev/migrie/f/non-terminal-content-elevation-warning 2021-11-15 10:39:36 -06:00
Mike Griese
bad27a97ba THIS NEEDS TO GO TO THE PARENT
(cherry picked from commit b499d44d4baf21c279dbb9f3a766bc9c37528b62)
2021-11-11 17:05:28 -06:00
Mike Griese
97d11d1bd3 Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-11-11 13:01:37 -06:00
Mike Griese
7f03d4d1ea dustins nits 2021-11-11 12:58:50 -06:00
Mike Griese
33e96e7e66 mitigate a TOCTOU 2021-11-11 12:56:05 -06:00
Mike Griese
999f21fcf8 Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-11-11 11:55:05 -06:00
Mike Griese
08cbd16d47 the last of it? 2021-11-10 10:17:41 -06:00
Mike Griese
db9cbf3fa8 spell 2021-11-10 10:16:31 -06:00
Mike Griese
7024f44c96 whoops 2021-11-10 10:01:52 -06:00
Mike Griese
1c66877b72 pwsh core fixed too 2021-11-09 12:44:05 -06:00
Mike Griese
5253c114ae make sure event handlers get replaced, too 2021-11-09 11:57:46 -06:00
Mike Griese
fdc574929b make text selectable 2021-11-09 10:34:54 -06:00
Mike Griese
c09bdbd25e Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-11-09 10:32:47 -06:00
Mike Griese
ce6a9c571b Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-11-09 08:24:25 -06:00
Mike Griese
a93d17ef09 I believe this is the rest of the comments 2021-11-09 08:24:18 -06:00
Mike Griese
4f16dfb5fd many comments 2021-11-09 08:01:47 -06:00
Mike Griese
b21287140d this is the right way to initialize the unique_hlocal_security_descriptor 2021-11-09 07:47:12 -06:00
Mike Griese
25b2675d8d this works really quite well 2021-11-09 06:24:16 -06:00
Mike Griese
fd849a5241 trying to do the thing eryksun mentioned. This seems to actually work to prevent non-admins from writing the file, and BOY is it simple. Still doesn't prevent the vim situation, but also do we need to prevent that footgun? probably 2021-11-08 14:30:07 -06:00
Mike Griese
4976a091a0 this is a collection of the trivial nits while I wait on a reply to the hard questions 2021-11-04 12:48:45 -05:00
Mike Griese
c90eb8763a good catch 2021-11-01 09:09:33 -05:00
Mike Griese
25c34dfcad Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-11-01 08:55:07 -05:00
Mike Griese
9b4ae9ec55 Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-11-01 08:53:07 -05:00
Mike Griese
3a8a83a810 last pr nits 2021-11-01 08:52:47 -05:00
Mike Griese
bdf08165d4 spel 2021-10-28 08:20:09 -05:00
Mike Griese
b9979ffaf8 Esc to dismiss too 2021-10-28 07:03:11 -05:00
Mike Griese
7fb490629b More cleanup 2021-10-27 16:04:32 -05:00
Mike Griese
d6d708796a Cleanup from the experimentation phase 2021-10-27 15:59:32 -05:00
Mike Griese
242de14722 Incredible that this works at all 2021-10-27 15:06:40 -05:00
Mike Griese
69f1068050 update appearance 2021-10-27 12:10:28 -05:00
Mike Griese
90b79624ca Merge remote-tracking branch 'origin/dev/lhecker/proxy-no-default-lib' into dev/migrie/f/non-terminal-content-elevation-warning 2021-10-27 11:55:21 -05:00
Leonard Hecker
fe5a78cff1 Fix OpenConsoleProxy for Debug builds 2021-10-27 18:35:29 +02:00
Mike Griese
21d6ffe89c Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-10-27 11:04:36 -05:00
Mike Griese
945c81d1df Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-10-27 10:38:52 -05:00
Mike Griese
faa06f807d Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-10-07 11:49:00 -05:00
Mike Griese
bf3c6e7029 spel is hard 2021-09-30 12:53:08 -05:00
Mike Griese
f49c3fca01 Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-30 12:49:03 -05:00
Mike Griese
ae99ce9c36 teh 2021-09-30 12:48:09 -05:00
Mike Griese
0e7217d354 Merge commit 'aea37520b3cdb1c1752a6c8e0ff598991518ce28' into dev/migrie/f/just-elevated-state-2 2021-09-30 12:47:33 -05:00
Mike Griese
aea37520b3 we want this 2021-09-30 12:47:03 -05:00
Mike Griese
3c1866ac53 Merge remote-tracking branch 'origin/dev/migrie/b/1.12-crash-on-exit' into dev/migrie/f/investigate-crashing 2021-09-30 11:28:32 -05:00
Mike Griese
48b20de4f4 Add some logging. Can't seem to get the crash to repro? 2021-09-30 11:15:35 -05:00
Mike Griese
9ff2775122 Merge branch 'dev/migrie/f/just-trying-something-on-just-elevated-state-2' into dev/migrie/f/just-elevated-state-2 2021-09-30 10:58:04 -05:00
Mike Griese
b4e0496eff cleanup 2021-09-30 10:27:57 -05:00
Mike Griese
ff333870fc Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-30 10:06:23 -05:00
Mike Griese
866832b665 This seemingly works the way I'd expect, going to merge into the warning dialog and check 2021-09-30 09:39:17 -05:00
Mike Griese
56992296bf Apply suggestions from code review
Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2021-09-30 08:25:16 -05:00
Mike Griese
d053f6cc9e Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-09-30 07:45:23 -05:00
Mike Griese
a751156fcc Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-28 10:53:35 -05:00
Mike Griese
620ee302fd Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2
Tossed out the AppState changes from #11083, since we're planning on just
  moving that to the Monarch anyways.
2021-09-28 10:36:29 -05:00
Mike Griese
abb847b4c7 pr nits from miniksa 2021-09-27 10:29:38 -05:00
Mike Griese
a3ac32ab25 derp 2021-09-22 15:57:44 -05:00
Mike Griese
5e9d0b8195 use the background from the control when we can 2021-09-22 15:49:41 -05:00
Mike Griese
62fe8235dc Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-22 14:50:12 -05:00
Mike Griese
5ff9a247d4 okay so I guess that's not a word 2021-09-22 14:49:46 -05:00
Mike Griese
7e2b371dae Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-22 14:48:29 -05:00
Mike Griese
02e9871f2a Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-09-22 14:46:25 -05:00
Mike Griese
eee657b502 fix hot reloading for this file 2021-09-22 14:37:33 -05:00
Mike Griese
a6e044d91c pr nits 2021-09-22 14:37:32 -05:00
Mike Griese
f3738f5c1b Move window state, approvedCommandlines into user-state.json
This fixes the issue I had in the last commit. It's a little weird, but gets
  rid of the muckiness of layering. Things that are local to one elevation level
  won't pollute the other, and we don't need to worry about layering or where
  they came from. Just write shared state to `state.json`, and window state to
  `elevated-state`/`user-state`
2021-09-22 14:37:32 -05:00
Mike Griese
7e2e4eaf49 I think this works ALMOST as I want
* [x] delete all state, open terminal elevated - generated profiles go to the correct place, approved commandlines go to the elevated one.
  * [x] delete some dynamic profiles, open the terminal - they don't resurrect in either IL
  * [ ] GAH saving a window layout unelevated, then trying to save one elevated will blow away the unelevated one
2021-09-22 14:37:25 -05:00
Mike Griese
8635537ebc fix hot reloading for this file 2021-09-22 14:35:02 -05:00
Mike Griese
de9dc32aa0 pr nits 2021-09-22 12:26:33 -05:00
Mike Griese
64d02f2b2b Move window state, approvedCommandlines into user-state.json
This fixes the issue I had in the last commit. It's a little weird, but gets
  rid of the muckiness of layering. Things that are local to one elevation level
  won't pollute the other, and we don't need to worry about layering or where
  they came from. Just write shared state to `state.json`, and window state to
  `elevated-state`/`user-state`
2021-09-22 12:07:34 -05:00
Mike Griese
94c4cca176 I think this works ALMOST as I want
* [x] delete all state, open terminal elevated - generated profiles go to the correct place, approved commandlines go to the elevated one.
  * [x] delete some dynamic profiles, open the terminal - they don't resurrect in either IL
  * [ ] GAH saving a window layout unelevated, then trying to save one elevated will blow away the unelevated one
2021-09-22 11:23:33 -05:00
Mike Griese
b2796019f8 Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-22 10:03:45 -05:00
Mike Griese
b755eb0f20 Merge remote-tracking branch 'origin/main' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-22 10:03:37 -05:00
Mike Griese
b1b1befeb9 this is a crazy idea that I hate but gotta start somewhere 2021-09-22 10:03:07 -05:00
Mike Griese
507a48ed68 Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-09-22 08:27:01 -05:00
Mike Griese
5a8e27e60a Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-20 12:42:59 -05:00
Mike Griese
9b3b9e0109 remove baseapplicationstate and just merge it back in 2021-09-20 12:42:41 -05:00
Mike Griese
7f9f75cab3 gah, I might have broke persisting window state 2021-09-20 12:11:30 -05:00
Mike Griese
d0f05f60e9 Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-20 11:38:19 -05:00
Mike Griese
56850639c5 Merge remote-tracking branch 'origin/main' into dev/migrie/f/just-elevated-state-2 2021-09-20 11:34:59 -05:00
Mike Griese
a4acdeb5f2 blindly remove ElevatedState 2021-09-20 11:34:11 -05:00
Mike Griese
56d5f9ee3a every day I'm mangling 2021-09-14 16:44:38 -05:00
Mike Griese
d944a68ded manually allow env var parsing. Remember that wsl needs manual allows too 2021-09-14 16:07:47 -05:00
Mike Griese
723037ef99 fix the focus thing, frick the env vars thing 2021-09-14 15:47:01 -05:00
Mike Griese
54a002762a comments 2021-09-14 15:36:03 -05:00
Mike Griese
47d55a8fd0 don't do the lookup for things in system32 2021-09-14 15:22:20 -05:00
Mike Griese
edd71265d8 Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-14 12:16:25 -05:00
Mike Griese
6757452d6d fix the tests 2021-09-14 12:14:50 -05:00
Mike Griese
4e69a32de7 bunch of new allowed words 2021-09-14 06:01:24 -05:00
Mike Griese
da0cc7bae5 todo! in the code 2021-09-14 05:59:54 -05:00
Mike Griese
51e0473560 minor nits
(cherry picked from commit 306ad30753)
2021-09-14 05:49:10 -05:00
Mike Griese
c106f64bc7 🤦
(cherry picked from commit 00c7647594)
2021-09-14 05:49:04 -05:00
Mike Griese
6be697221d This is everything from dev/migrie/f/non-terminal-content-elevation-warning for specifically ElevatedState
(cherry picked from commit 97b0f06504)
2021-09-14 05:48:56 -05:00
Mike Griese
d6c2fb593d THis fixes #7754 2021-09-14 05:20:45 -05:00
Mike Griese
1e3a319314 more unique_sid's, and m,ore comments 2021-09-13 14:32:46 -05:00
Mike Griese
4da965f901 Merge remote-tracking branch 'origin/main' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-13 14:20:03 -05:00
Mike Griese
4f697eca92 I thing this was unneeded 2021-09-13 12:11:04 -05:00
Mike Griese
1111d41347 This works to do the 'blow the file away when permissions have changed' thing 2021-09-13 11:45:11 -05:00
Mike Griese
6265f4f1d7 this looks like it checks the permissions as we'd expect 2021-09-09 14:00:51 -05:00
Mike Griese
7854abe0a3 I bet that's what I was doing wrong. The rename is just dandy, it don't care about elevation or none of that, so the unelevated terminal could atomically rewrite the elevated file, which isn't what we wanted. 2021-09-09 12:09:06 -05:00
Mike Griese
9a1cf5ac6e bunch of dead ends 2021-09-09 12:03:42 -05:00
Mike Griese
aef422d5f1 This is definitely not right.
Sublime can delete the file just fine (and write any old file in it's place)
  Even we can modify the file when running unelevated, which is **B**ad.

  So there's gotta be some way to allow _us_ to write the file only when elevated
2021-09-09 10:23:53 -05:00
Mike Griese
8569211d0f Now, we can update the file after it's created 2021-09-09 10:18:22 -05:00
Mike Griese
721b6367a2 unfortunately, we can't _write_ this file... 2021-09-09 10:11:52 -05:00
Mike Griese
5197dc4e50 this worked, nice 2021-09-09 08:56:53 -05:00
Mike Griese
880222dc1b This file isn't even readable by admins, so maybe that's bad 2021-09-09 08:23:59 -05:00
Mike Griese
447c2f9d4f I think this creates a test file that's only accessible by SYSTEM. Asked raymond chen for help. 2021-09-08 15:51:21 -05:00
Mike Griese
b592155d2b Merge remote-tracking branch 'origin/main' into dev/migrie/f/non-terminal-content-elevation-warning 2021-09-08 11:50:56 -05:00
Mike Griese
64898b1caf update other panes too 2021-09-02 11:50:33 -05:00
Mike Griese
e5dc64e085 Hot-reload the elevated state? 2021-09-02 11:12:07 -05:00
Mike Griese
58c6646132 Format that dialog with the actual commandline 2021-09-02 11:01:11 -05:00
Mike Griese
9b32681ae1 This works to prompt before splitting a pane 2021-09-02 10:09:22 -05:00
Mike Griese
7f29e1e268 More things we might need for Non-Terminal content, #997 2021-09-02 10:09:05 -05:00
Mike Griese
736a351c27 This works amazingly well 2021-09-01 17:08:00 -05:00
Mike Griese
631cdf7b18 Who ever said nested lambdas is a bad thing? 2021-09-01 16:42:36 -05:00
Mike Griese
7fb7d64b91 These are things I might need for #997 2021-09-01 16:38:58 -05:00
Mike Griese
1ee3522cd8 Allow a TerminalTab to have a UserControl 2021-09-01 15:27:30 -05:00
Mike Griese
ed1cf2aeac add the boilerplate for a custom content dialog like thing 2021-09-01 14:57:41 -05:00
Mike Griese
c66a56656e Allow a Pane to host a UserControl instead of a TermControl 2021-09-01 12:53:46 -05:00
Mike Griese
14d21f492b nits, cleanup 2021-09-01 12:52:45 -05:00
Mike Griese
ccbcb425da Merge remote-tracking branch 'origin/main' into dev/migrie/f/elevation-warning 2021-08-31 16:16:02 -05:00
Mike Griese
2857324777 proof of concept add a dialog to pop when opening new tabs 2021-08-31 16:15:49 -05:00
Mike Griese
eb243f5e11 Split ApplicationState into a Base and add an Elevated version 2021-08-31 16:15:22 -05:00
Mike Griese
42c3eea136 pull application state members into a base class 2021-08-30 12:47:10 -05:00
33 changed files with 2039 additions and 911 deletions

15
.github/actions/spelling/README.md vendored Normal file
View 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.

View File

@@ -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>

View File

@@ -1,47 +1,66 @@
admins
apc
allcolors
Apc
apc
breadcrumb
breadcrumbs
bsd
calt
ccmp
changelog
clickable
clig
CMMI
copyable
cybersecurity
dalet
dcs
Dcs
dcs
dialytika
dje
downside
downsides
dze
dzhe
EDDB
EDDC
Enum'd
Fitt
formattings
FTCS
ftp
fvar
gantt
gcc
geeksforgeeks
ghe
github
gje
godbolt
hostname
hostnames
https
hyperlink
hyperlinking
hyperlinks
iconify
img
inlined
It'd
kje
libfuzzer
libuv
liga
lje
Llast
llvm
Lmid
locl
lol
lorem
Lorigin
maxed
minimalistic
mkmk
mnt
mru
@@ -50,6 +69,7 @@ noreply
ogonek
ok'd
overlined
pipeline
postmodern
ptys
qof
@@ -64,17 +84,25 @@ runtimes
shcha
slnt
Sos
ssh
timeline
timelines
timestamped
TLDR
tokenizes
tonos
toolset
tshe
ubuntu
uiatextrange
UIs
und
unregister
versioned
vsdevcmd
We'd
wildcards
XBox
YBox
yeru
zhe

View File

@@ -5,21 +5,23 @@ aclapi
alignas
alignof
APPLYTOSUBMENUS
appxrecipe
bitfield
bitfields
BUILDBRANCH
BUILDMSG
BUILDNUMBER
BYPOSITION
BYCOMMAND
BYPOSITION
charconv
CLASSNOTAVAILABLE
CLOSEAPP
cmdletbinding
COLORPROPERTY
colspan
COMDLG
comparand
commandlinetoargv
comparand
cstdint
CXICON
CYICON
@@ -28,8 +30,14 @@ dataobject
dcomp
DERR
dlldata
DNE
DONTADDTORECENT
DWMSBT
DWMWA
DWMWA
DWORDLONG
endfor
ENDSESSION
enumset
environstrings
EXPCMDFLAGS
@@ -43,12 +51,16 @@ fullkbd
futex
GETDESKWALLPAPER
GETHIGHCONTRAST
GETMOUSEHOVERTIME
Hashtable
HIGHCONTRASTON
HIGHCONTRASTW
hotkeys
href
hrgn
HTCLOSE
hwinsta
HWINSTA
IActivation
IApp
IAppearance
@@ -65,19 +77,22 @@ IDirect
IExplorer
IFACEMETHOD
IFile
IGraphics
IInheritable
IMap
IMonarch
IObject
iosfwd
IPackage
IPeasant
isspace
ISetup
isspace
IStorage
istream
IStringable
ITab
ITaskbar
itow
IUri
IVirtual
KEYSELECT
@@ -86,18 +101,27 @@ llabs
llu
localtime
lround
Lsa
lsass
LSHIFT
LTGRAY
MAINWINDOW
memchr
memicmp
MENUCOMMAND
MENUDATA
MENUINFO
MENUITEMINFOW
memicmp
mptt
mmeapi
MOUSELEAVE
mov
mptt
msappx
MULTIPLEUSE
NCHITTEST
NCLBUTTONDBLCLK
NCMOUSELEAVE
NCMOUSEMOVE
NCRBUTTONDBLCLK
NIF
NIN
@@ -115,6 +139,8 @@ oaidl
ocidl
ODR
offsetof
ofstream
onefuzz
osver
OSVERSIONINFOEXW
otms
@@ -122,14 +148,17 @@ OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PATINVERT
PEXPLICIT
PICKFOLDERS
pmr
ptstr
QUERYENDSESSION
rcx
REGCLS
RETURNCMD
rfind
ROOTOWNER
roundf
RSHIFT
SACL
@@ -139,6 +168,7 @@ serializer
SETVERSION
SHELLEXECUTEINFOW
shobjidl
SHOWHIDE
SHOWMINIMIZED
SHOWTIP
SINGLEUSE
@@ -159,24 +189,37 @@ Stubless
Subheader
Subpage
syscall
SYSTEMBACKDROP
TABROW
TASKBARCREATED
TBPF
THEMECHANGED
tlg
TME
tmp
tmpdir
tolower
toupper
TRACKMOUSEEVENT
TTask
TVal
UChar
UFIELD
ULARGE
UOI
UPDATEINIFILE
userenv
USEROBJECTFLAGS
Viewbox
virtualalloc
wcsstr
wcstoui
winmain
winsta
winstamin
wmemcmp
wpc
WSF
wsregex
wwinmain
xchg

View File

@@ -19,6 +19,7 @@ CPRs
cryptbase
DACL
DACLs
defaultlib
diffs
disposables
dotnetfeed
@@ -27,6 +28,8 @@ DWINRT
enablewttlogging
Intelli
IVisual
libucrt
libucrtd
LKG
LOCKFILE
Lxss
@@ -36,8 +39,10 @@ microsoftonline
MSAA
msixbundle
MSVC
MSVCP
muxc
netcore
Onefuzz
osgvsowi
PFILETIME
pgc
@@ -62,6 +67,8 @@ systemroot
taskkill
tasklist
tdbuildteamid
ucrt
ucrtd
unvirtualized
VCRT
vcruntime

View File

@@ -1,13 +1,16 @@
Anup
austdi
arkthur
Ballmer
bhoj
Bhojwani
Bluloco
carlos
dhowett
Diviness
dsafa
duhowett
DXP
ekg
eryksun
ethanschoonover
@@ -21,6 +24,7 @@ Hernan
Howett
Illhardt
iquilezles
italo
jantari
jerrysh
Kaiyu
@@ -34,7 +38,9 @@ leonmsft
Lepilleur
lhecker
lukesampson
Macbook
Manandhar
masserano
mbadolato
Mehrain
menger
@@ -63,12 +69,16 @@ Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Walisch
WDX
Wellons
Wirt
Wojciech

View 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
(['"]|&quot;)[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-)/

View File

@@ -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,53 @@ 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/
^doc/reference/master-sequence-list.csv$
@@ -76,6 +112,6 @@ SUMS$
^src/tools/texttests/fira\.txt$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^src/types/ut_types/UtilsTests.cpp$
^\.github/actions/spelling/
^\.gitignore$
^\XamlStyler.json$
^tools/ReleaseEngineering/ServicingPipeline.ps1$
ignore$
SUMS$

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,6 @@
http
www
easyrgb
php
ecma
rapidtables
WCAG
freedesktop
ycombinator
robertelder
kovidgoyal
leonerd
fixterms
winui
appshellintegration
mdtauk
cppreference
gfycat
Guake

View 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

View File

@@ -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
@@ -25,3 +20,77 @@ std::memory_order_[\w]+
D2DERR_SHADER_COMPILE_FAILED
TIL_FEATURE_[0-9A-Z_]+
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

View File

@@ -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.*

View File

@@ -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 }}

View File

@@ -43,7 +43,8 @@
<ClCompile Include="CommandlineTest.cpp" />
<ClCompile Include="SettingsTests.cpp" />
<ClCompile Include="TabTests.cpp" />
<ClCompile Include="FilteredCommandTests.cpp" />
<ClCompile Include="TrustCommandlineTests.cpp" />
<ClCompile Include="FilteredCommandTests.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>

View File

@@ -0,0 +1,123 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// A series of tests for the TerminalPage::_isTrustedCommandline function.
// That's a heuristic function for deciding if we should automatically trust
// certain commandlines by default. The logic in there is weird and there are
// lots of edge cases, so it's easier to just write a unit test.
#include "pch.h"
#include "../TerminalApp/TerminalPage.h"
using namespace Microsoft::Console;
using namespace TerminalApp;
using namespace winrt::TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Text;
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
using IInspectable = Windows::Foundation::IInspectable;
}
namespace TerminalAppLocalTests
{
class TrustCommandlineTests
{
BEGIN_TEST_CLASS(TrustCommandlineTests)
END_TEST_CLASS()
TEST_METHOD(SimpleTests);
TEST_METHOD(TestCommandlineWithArgs);
TEST_METHOD(TestCommandlineWithSpaces);
TEST_METHOD(TestCommandlineWithEnvVars);
TEST_METHOD(WslTests);
TEST_METHOD(TestPwshLocation);
bool trust(std::wstring_view cmdline);
};
bool TrustCommandlineTests::trust(std::wstring_view cmdline)
{
return implementation::TerminalPage::_isTrustedCommandline(cmdline);
}
void TrustCommandlineTests::SimpleTests()
{
VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\cmd.exe"));
VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"));
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\i-definitely-don't-exist.exe"));
Log::Comment(L"These are not fully qualified, and _shouldn't_ be trusted");
VERIFY_IS_FALSE(trust(L"cmd.exe"));
VERIFY_IS_FALSE(trust(L"powershell.exe"));
}
void TrustCommandlineTests::TestCommandlineWithArgs()
{
Log::Comment(L"These are sneaky things that _shouldn't_ be trusted");
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /k echo Boo!"));
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /k echo Boo! & cmd.exe"));
}
void TrustCommandlineTests::TestCommandlineWithSpaces()
{
Log::Comment(L"This is a valid place for powershell to live, and the space can be tricky");
VERIFY_IS_TRUE(trust(L"C:\\Program Files\\PowerShell\\7\\pwsh.exe"));
Log::Comment(L"These are sneaky things that _shouldn't_ be trusted");
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System 32\\cmd.exe"));
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\ cmd.exe"));
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /c cmd.exe"));
}
void TrustCommandlineTests::TestCommandlineWithEnvVars()
{
Log::Comment(L"Make sure we auto-expand environment variables");
VERIFY_IS_TRUE(trust(L"%WINDIR%\\system32\\cmd.exe"));
VERIFY_IS_TRUE(trust(L"%WINDIR%\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"));
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe"));
}
void TrustCommandlineTests::WslTests()
{
Log::Comment(L"We are explicitly deciding to not auto-approve "
L"`wsl.exe -d distro`-like commandlines. If we change this"
L" policy, remove this test.");
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\wsl"));
VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\wsl.exe"), L"This we will trust though, since it's an exe in system32");
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\wsl.exe -d Ubuntu"));
VERIFY_IS_FALSE(trust(L"wsl.exe"));
}
void TrustCommandlineTests::TestPwshLocation()
{
Log::Comment(L"Test various locations that pwsh.exe can be in");
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe"));
VERIFY_IS_TRUE(trust(L"%LOCALAPPDATA%\\Microsoft\\WindowsApps\\pwsh.exe"));
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\10\\pwsh.exe"));
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\7.1.5\\pwsh.exe"));
Log::Comment(L"These are sneaky things that _shouldn't_ be trusted");
VERIFY_IS_FALSE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe bad-stuff pwsh.exe"));
VERIFY_IS_FALSE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe bad-stuff c:\\pwsh.exe"));
VERIFY_IS_FALSE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe bad-stuff c:\\ %ProgramFiles%\\PowerShell\\7\\pwsh.exe"));
}
}

View File

@@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "pch.h"
#include "AdminWarningPlaceholder.h"
#include "AdminWarningPlaceholder.g.cpp"
#include <LibraryResources.h>
using namespace winrt::Windows::UI::Xaml;
namespace winrt::TerminalApp::implementation
{
AdminWarningPlaceholder::AdminWarningPlaceholder(const winrt::Microsoft::Terminal::Control::TermControl& control, const winrt::hstring& cmdline) :
_control{ control },
_Commandline{ cmdline }
{
InitializeComponent();
// If the content we're hosting is a TermControl, then use the control's
// BG as our BG, to give the impression that it's there, under the
// dialog.
if (const auto termControl{ control.try_as<winrt::Microsoft::Terminal::Control::TermControl>() })
{
RootGrid().Background(termControl.BackgroundBrush());
}
}
void AdminWarningPlaceholder::_primaryButtonClick(winrt::Windows::Foundation::IInspectable const& /*sender*/,
RoutedEventArgs const& e)
{
_PrimaryButtonClickedHandlers(*this, e);
}
void AdminWarningPlaceholder::_cancelButtonClick(winrt::Windows::Foundation::IInspectable const& /*sender*/,
RoutedEventArgs const& e)
{
_CancelButtonClickedHandlers(*this, e);
}
winrt::Windows::UI::Xaml::Controls::UserControl AdminWarningPlaceholder::Control()
{
return _control;
}
// Method Description:
// - Move the focus to the cancel button by default. This has the LOAD
// BEARING side effect of also triggering Narrator to read out the
// contents of the dialog. It's unclear why doing this works, but it does.
// - Using a LayoutUpdated event to trigger the focus change when we're
// added to the UI tree did not seem to work.
// - Whoever is adding us to the UI tree is responsible for calling this!
// Arguments:
// - <none>
// Return Value:
// - <none>
void AdminWarningPlaceholder::FocusOnLaunch()
{
CancelButton().Focus(FocusState::Programmatic);
}
winrt::hstring AdminWarningPlaceholder::ControlName()
{
return RS_(L"AdminWarningPlaceholderName");
}
void AdminWarningPlaceholder::_keyUpHandler(IInspectable const& /*sender*/,
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
{
// If the user presses escape, close the dialog (without confirming)
const auto key = e.OriginalKey();
if (key == winrt::Windows::System::VirtualKey::Escape)
{
_CancelButtonClickedHandlers(*this, e);
e.Handled(true);
}
}
}

View File

@@ -0,0 +1,51 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- AdminWarningPlaceholder
Abstract:
- The AdminWarningPlaceholder is a control used to fill space in a pane and
present a warning to the user. It holds on to a real control that it should be
replaced with. It looks just like a ContentDialog, except it exists per-pane,
whereas a ContentDialog can only be added to take up the whole window.
- The caller should make sure to bind our PrimaryButtonClicked and
CancelButtonClicked events, to be informed as to which was pressed.
Author(s):
- Mike Griese - September 2021
--*/
#pragma once
#include "AdminWarningPlaceholder.g.h"
#include "../../cascadia/inc/cppwinrt_utils.h"
namespace winrt::TerminalApp::implementation
{
struct AdminWarningPlaceholder : AdminWarningPlaceholderT<AdminWarningPlaceholder>
{
AdminWarningPlaceholder(const winrt::Microsoft::Terminal::Control::TermControl& control, const winrt::hstring& cmdline);
void FocusOnLaunch();
winrt::Windows::UI::Xaml::Controls::UserControl Control();
winrt::hstring ControlName();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Commandline, _PropertyChangedHandlers);
TYPED_EVENT(PrimaryButtonClicked, TerminalApp::AdminWarningPlaceholder, winrt::Windows::UI::Xaml::RoutedEventArgs);
TYPED_EVENT(CancelButtonClicked, TerminalApp::AdminWarningPlaceholder, winrt::Windows::UI::Xaml::RoutedEventArgs);
private:
friend struct AdminWarningPlaceholderT<AdminWarningPlaceholder>; // friend our parent so it can bind private event handlers
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
void _primaryButtonClick(winrt::Windows::Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void _cancelButtonClick(winrt::Windows::Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void _keyUpHandler(Windows::Foundation::IInspectable const& sender,
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
};
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
[default_interface] runtimeclass AdminWarningPlaceholder : Windows.UI.Xaml.Controls.UserControl,
Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Commandline { get; };
String ControlName { get; };
}
}

View File

@@ -0,0 +1,97 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<UserControl x:Class="TerminalApp.AdminWarningPlaceholder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
AutomationProperties.AccessibilityView="Content"
AutomationProperties.IsDialog="True"
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
PreviewKeyUp="_keyUpHandler"
mc:Ignorable="d">
<!--
We have to use two grids to be tricky here:
- The outer grid will get its background from the control it hosts, and
expands to fit its container. This will make it look like the background
fills the space available.
- The inner grid is set to Center,Center, so that the "dialog" appears
centered
-->
<Grid x:Name="RootGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center">
<Border Margin="8,8,8,8"
Padding="16,8,16,8"
AllowFocusOnInteraction="True"
AutomationProperties.AccessibilityView="Raw"
AutomationProperties.IsDialog="True"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
BorderBrush="{ThemeResource SystemAccentColor}"
BorderThickness="2,2,2,2"
CornerRadius="{ThemeResource OverlayCornerRadius}">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="ApproveCommandlineWarningTitle"
x:Uid="ApproveCommandlineWarningTitle"
Padding="0,0,0,16"
HorizontalAlignment="Left"
FontSize="20"
FontWeight="Normal"
IsTextSelectionEnabled="True"
TextWrapping="WrapWholeWords" />
<TextBlock x:Name="PrefixTextBlock"
x:Uid="ApproveCommandlineWarningPrefixTextBlock"
HorizontalAlignment="Left"
IsTextSelectionEnabled="True"
TextWrapping="WrapWholeWords" />
<TextBlock x:Name="CommandlineText"
Margin="0,16,0,16"
HorizontalAlignment="Left"
FontFamily="Cascadia Mono"
IsTextSelectionEnabled="True"
Text="{x:Bind Commandline, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<TextBlock x:Name="SuffixTextBlock"
x:Uid="ApproveCommandlineWarningSuffixTextBlock"
HorizontalAlignment="Left"
IsTextSelectionEnabled="True"
TextWrapping="WrapWholeWords" />
<Grid Margin="0,8,0,8"
HorizontalAlignment="Stretch"
XYFocusKeyboardNavigation="Enabled">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="PrimaryButton"
x:Uid="ApproveCommandlineWarning_PrimaryButton"
Grid.Column="0"
Margin="0,0,8,0"
HorizontalAlignment="Stretch"
Click="_primaryButtonClick"
IsTabStop="True"
Style="{StaticResource AccentButtonStyle}" />
<Button x:Name="CancelButton"
x:Uid="ApproveCommandlineWarning_CancelButton"
Grid.Column="1"
HorizontalAlignment="Stretch"
Click="_cancelButtonClick"
IsTabStop="True" />
</Grid>
</StackPanel>
</Border>
</Grid>
</Grid>
</UserControl>

View File

@@ -34,7 +34,7 @@ static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Wi
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
Pane::Pane(const Profile& profile, const Controls::UserControl& control, const bool lastFocused) :
_control{ control },
_lastActive{ lastFocused },
_profile{ profile }
@@ -42,8 +42,11 @@ Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFo
_root.Children().Append(_borderFirst);
_borderFirst.Child(_control);
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
if (const auto& termControl{ _control.try_as<TermControl>() })
{
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
}
// On the first Pane's creation, lookup resources we'll use to theme the
// Pane, including the brushed to use for the focused/unfocused border
@@ -125,11 +128,23 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
assert(_IsLeaf());
NewTerminalArgs args{};
auto controlSettings = _control.Settings().as<TerminalSettings>();
auto termControl{ _control.try_as<TermControl>() };
if (!termControl)
{
if (auto adminWarning{ _control.try_as<AdminWarningPlaceholder>() })
{
termControl = adminWarning.Content().try_as<TermControl>();
}
}
if (!termControl)
{
return nullptr;
}
auto controlSettings = termControl.Settings().as<TerminalSettings>();
args.Profile(controlSettings.ProfileName());
// If we know the user's working directory use it instead of the profile.
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
if (const auto dir = termControl.WorkingDirectory(); !dir.empty())
{
args.StartingDirectory(dir);
}
@@ -832,6 +847,40 @@ bool Pane::SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second)
return false;
}
Controls::UserControl Pane::ReplaceControl(const Controls::UserControl& control)
{
if (!_IsLeaf())
{
return nullptr;
}
// Remove old control's event handlers
const auto& oldControl = _control;
_gotFocusRevoker.revoke();
_lostFocusRevoker.revoke();
if (const auto& oldTermControl{ _control.try_as<TermControl>() })
{
oldTermControl.ConnectionStateChanged(_connectionStateChangedToken);
oldTermControl.WarningBell(_warningBellToken);
}
_control = control;
_borderFirst.Child(_control);
// Register an event with the control to have it inform us when it gains focus.
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
if (const auto& termControl{ _control.try_as<TermControl>() })
{
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
}
return oldControl;
}
// Method Description:
// - Given two panes' offsets, test whether the `direction` side of first is adjacent to second.
// Arguments:
@@ -1079,8 +1128,12 @@ void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundatio
{
return;
}
const auto newConnectionState = _control.ConnectionState();
const auto& termControl{ _control.try_as<TermControl>() };
if (!termControl)
{
return;
}
const auto newConnectionState = termControl.ConnectionState();
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
if (newConnectionState < ConnectionState::Closed)
@@ -1123,7 +1176,9 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
{
return;
}
if (_profile)
const auto& termControl{ _control.try_as<TermControl>() };
if (_profile && termControl)
{
// We don't want to do anything if nothing is set, so check for that first
if (static_cast<int>(_profile.BellStyle()) != 0)
@@ -1137,7 +1192,7 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
{
_control.BellLightOn();
termControl.BellLightOn();
}
// raise the event with the bool value corresponding to the taskbar flag
@@ -1197,7 +1252,11 @@ void Pane::Shutdown()
std::unique_lock lock{ _createCloseLock };
if (_IsLeaf())
{
_control.Close();
const auto& termControl{ _control.try_as<TermControl>() };
if (termControl)
{
termControl.Close();
}
}
else
{
@@ -1207,7 +1266,7 @@ void Pane::Shutdown()
}
// Method Description:
// - Get the root UIElement of this pane. There may be a single TermControl as a
// - Get the root UIElement of this pane. There may be a single UserControl as a
// child, or an entire tree of grids and panes as children of this element.
// Arguments:
// - <none>
@@ -1266,7 +1325,7 @@ TermControl Pane::GetLastFocusedTerminalControl()
{
if (p->_IsLeaf())
{
return p->_control;
return p->GetTerminalControl();
}
pane = p;
}
@@ -1274,7 +1333,7 @@ TermControl Pane::GetLastFocusedTerminalControl()
}
return _firstChild->GetLastFocusedTerminalControl();
}
return _control;
return GetTerminalControl();
}
// Method Description:
@@ -1283,8 +1342,15 @@ TermControl Pane::GetLastFocusedTerminalControl()
// Arguments:
// - <none>
// Return Value:
// - nullptr if this Pane is a parent, otherwise the TermControl of this Pane.
TermControl Pane::GetTerminalControl()
// - nullptr if this Pane is a parent or isn't hosting a Terminal, otherwise the
// TermControl of this Pane.
TermControl Pane::GetTerminalControl() const
{
auto control{ GetUserControl() };
return control ? control.try_as<TermControl>() : nullptr;
}
Controls::UserControl Pane::GetUserControl() const
{
return _IsLeaf() ? _control : nullptr;
}
@@ -1457,9 +1523,13 @@ void Pane::_FocusFirstChild()
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
{
assert(_IsLeaf());
const auto& termControl{ _control.try_as<TermControl>() };
if (!termControl)
{
return;
}
_profile = profile;
auto controlSettings = _control.Settings().as<TerminalSettings>();
auto controlSettings = termControl.Settings().as<TerminalSettings>();
// Update the parent of the control's settings object (and not the object itself) so
// that any overrides made by the control don't get affected by the reload
controlSettings.SetParent(settings.DefaultSettings());
@@ -1472,8 +1542,8 @@ void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Pr
// sure the unfocused settings inherit from that.
unfocusedSettings.SetParent(controlSettings);
}
_control.UnfocusedAppearance(unfocusedSettings);
_control.UpdateSettings();
termControl.UnfocusedAppearance(unfocusedSettings);
termControl.UpdateSettings();
}
// Method Description:
@@ -1614,8 +1684,12 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
_id = remainingChild->Id();
// Add our new event handler before revoking the old one.
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
const auto& termControl{ _control.try_as<TermControl>() };
if (termControl)
{
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
}
// Revoke the old event handlers. Remove both the handlers for the panes
// themselves closing, and remove their handlers for their controls
@@ -1629,8 +1703,11 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
closedChild->WalkTree([](auto p) {
if (p->_IsLeaf())
{
p->_control.ConnectionStateChanged(p->_connectionStateChangedToken);
p->_control.WarningBell(p->_warningBellToken);
if (const auto& closedControl{ p->_control.try_as<TermControl>() })
{
closedControl.ConnectionStateChanged(p->_connectionStateChangedToken);
closedControl.WarningBell(p->_warningBellToken);
}
}
return false;
});
@@ -1638,15 +1715,19 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
closedChild->Closed(closedChildClosedToken);
remainingChild->Closed(remainingChildClosedToken);
remainingChild->_control.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
remainingChild->_control.WarningBell(remainingChild->_warningBellToken);
if (const auto& remainingControl{ remainingChild->_control.try_as<TermControl>() })
{
remainingControl.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
remainingControl.WarningBell(remainingChild->_warningBellToken);
}
// If we or either of our children was focused, we want to take that
// focus from them.
_lastActive = _lastActive || _firstChild->_lastActive || _secondChild->_lastActive;
// Remove all the ui elements of the remaining child. This'll make sure
// we can re-attach the TermControl to our Grid.
// we can re-attach the UserControl to our Grid.
remainingChild->_root.Children().Clear();
remainingChild->_borderFirst.Child(nullptr);
@@ -1657,7 +1738,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
_root.ColumnDefinitions().Clear();
_root.RowDefinitions().Clear();
// Reattach the TermControl to our grid.
// Reattach the UserControl to our grid.
_root.Children().Append(_borderFirst);
_borderFirst.Child(_control);
@@ -1719,8 +1800,11 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
closedChild->WalkTree([](auto p) {
if (p->_IsLeaf())
{
p->_control.ConnectionStateChanged(p->_connectionStateChangedToken);
p->_control.WarningBell(p->_warningBellToken);
if (const auto& closedControl{ p->_control.try_as<TermControl>() })
{
closedControl.ConnectionStateChanged(p->_connectionStateChangedToken);
closedControl.WarningBell(p->_warningBellToken);
}
}
return false;
});
@@ -2468,11 +2552,14 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
if (_IsLeaf())
{
// revoke our handler - the child will take care of the control now.
_control.ConnectionStateChanged(_connectionStateChangedToken);
_connectionStateChangedToken.value = 0;
_control.WarningBell(_warningBellToken);
_warningBellToken.value = 0;
if (const auto& termControl{ _control.try_as<TermControl>() })
{
// revoke our handler - the child will take care of the control now.
termControl.ConnectionStateChanged(_connectionStateChangedToken);
termControl.WarningBell(_warningBellToken);
_connectionStateChangedToken.value = 0;
_warningBellToken.value = 0;
}
// Remove our old GotFocus handler from the control. We don't want the
// control telling us that it's now focused, we want it telling its new
@@ -2482,7 +2569,7 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
}
// Remove any children we currently have. We can't add the existing
// TermControl to a new grid until we do this.
// UserControl to a new grid until we do this.
_root.Children().Clear();
_borderFirst.Child(nullptr);
_borderSecond.Child(nullptr);
@@ -2860,8 +2947,13 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension
// If requested size is already snapped, then both returned values equal this value.
Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
{
const auto& termControl{ _control.try_as<TermControl>() };
if (_IsLeaf())
{
if (!termControl)
{
return { dimension, dimension };
}
// If we're a leaf pane, align to the grid of controlling terminal
const auto minSize = _GetMinSize();
@@ -2872,7 +2964,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
return { minDimension, minDimension };
}
float lower = _control.SnapDimensionToGrid(widthOrHeight, dimension);
float lower = termControl.SnapDimensionToGrid(widthOrHeight, dimension);
if (widthOrHeight)
{
lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0;
@@ -2892,7 +2984,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
}
else
{
const auto cellSize = _control.CharacterDimensions();
const auto cellSize = termControl.CharacterDimensions();
const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height);
return { lower, higher };
}
@@ -2937,26 +3029,39 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
// - <none>
void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& sizeNode) const
{
const auto& termControl{ _control.try_as<TermControl>() };
if (_IsLeaf())
{
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
// is true, see below).
if (sizeNode.isMinimumSize)
if (termControl)
{
// If the node is of its minimum size, this size might not be snapped (it might
// be, say, half a character, or fixed 10 pixels), so snap it upward. It might
// however be already snapped, so add 1 to make sure it really increases
// (not strictly necessary but to avoid surprises).
sizeNode.size = _CalcSnappedDimension(widthOrHeight, sizeNode.size + 1).higher;
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
// is true, see below).
if (sizeNode.isMinimumSize)
{
// If the node is of its minimum size, this size might not be snapped (it might
// be, say, half a character, or fixed 10 pixels), so snap it upward. It might
// however be already snapped, so add 1 to make sure it really increases
// (not strictly necessary but to avoid surprises).
sizeNode.size = _CalcSnappedDimension(widthOrHeight, sizeNode.size + 1).higher;
}
else
{
const auto cellSize = termControl.CharacterDimensions();
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
}
}
else
{
const auto cellSize = _control.CharacterDimensions();
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
// If we're a leaf that didn't have a TermControl, then just increment
// by one. We have to increment by _some_ value, because this is used in
// a while() loop to find the next bigger size we can snap to. But since
// a non-terminal control doesn't really care what size it's snapped to,
// we can just say "one pixel larger is the next snap point"
sizeNode.size += 1;
}
}
else
else // !_IsLeaf()
{
// We're a parent pane, so we have to advance dimension of our children panes. In
// fact, we advance only one child (chosen later) to keep the growth fine-grained.
@@ -3058,7 +3163,8 @@ Size Pane::_GetMinSize() const
{
if (_IsLeaf())
{
auto controlSize = _control.MinimumSize();
const auto& termControl{ _control.try_as<TermControl>() };
auto controlSize = termControl ? termControl.MinimumSize() : Size{ 1, 1 };
auto newWidth = controlSize.Width;
auto newHeight = controlSize.Height;
@@ -3244,7 +3350,10 @@ std::optional<SplitDirection> Pane::PreCalculateAutoSplit(const std::shared_ptr<
// - Returns true if the pane or one of its descendants is read-only
bool Pane::ContainsReadOnly() const
{
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
const auto& termControl{ GetTerminalControl() };
return termControl ?
termControl.ReadOnly() :
(_IsLeaf() ? false : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly()));
}
// Method Description:
@@ -3257,13 +3366,14 @@ bool Pane::ContainsReadOnly() const
// - <none>
void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states)
{
if (_IsLeaf())
const auto& termControl{ GetTerminalControl() };
if (termControl)
{
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
_control.TaskbarProgress()) };
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(termControl.TaskbarState(),
termControl.TaskbarProgress()) };
states.push_back(tbState);
}
else
else if (!_IsLeaf())
{
_firstChild->CollectTaskbarStates(states);
_secondChild->CollectTaskbarStates(states);

View File

@@ -56,7 +56,7 @@ class Pane : public std::enable_shared_from_this<Pane>
{
public:
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control,
const winrt::Windows::UI::Xaml::Controls::UserControl& control,
const bool lastFocused = false);
Pane(std::shared_ptr<Pane> first,
@@ -66,8 +66,9 @@ public:
const bool lastFocused = false);
std::shared_ptr<Pane> GetActivePane();
winrt::Windows::UI::Xaml::Controls::UserControl GetUserControl() const;
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const;
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
// Method Description:
@@ -126,6 +127,8 @@ public:
winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType);
std::shared_ptr<Pane> DetachPane(std::shared_ptr<Pane> pane);
winrt::Windows::UI::Xaml::Controls::UserControl ReplaceControl(const winrt::Windows::UI::Xaml::Controls::UserControl& control);
int GetLeafPaneCount() const noexcept;
void Maximize(std::shared_ptr<Pane> zoomedPane);
@@ -200,7 +203,8 @@ 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::Windows::UI::Xaml::Controls::UserControl _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;

View File

@@ -504,6 +504,24 @@
<data name="MultiLinePasteDialog.Title" xml:space="preserve">
<value>Warning</value>
</data>
<data name="ApproveCommandlineWarningPrefixTextBlock.Text" xml:space="preserve">
<value>You are about to execute the following command-line:</value>
</data>
<data name="ApproveCommandlineWarningSuffixTextBlock.Text" xml:space="preserve">
<value>Do you wish to continue?</value>
</data>
<data name="ApproveCommandlineWarning_PrimaryButton.Content" xml:space="preserve">
<value>Allow command-line</value>
</data>
<data name="ApproveCommandlineWarning_CancelButton.Content" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="ApproveCommandlineWarningTitle.Text" xml:space="preserve">
<value>Warning</value>
</data>
<data name="AdminWarningPlaceholderName" xml:space="preserve">
<value>Elevated command-line warning</value>
</data>
<data name="CommandPalette_SearchBox.PlaceholderText" xml:space="preserve">
<value>Type a command name...</value>
</data>

View File

@@ -16,6 +16,7 @@
#include <LibraryResources.h>
#include "TabRowControl.h"
#include "AdminWarningPlaceholder.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "SettingsTab.h"

View File

@@ -63,6 +63,9 @@
<Page Include="CommandPalette.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="AdminWarningPlaceholder.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<!-- ========================= Headers ======================== -->
<ItemGroup>
@@ -141,6 +144,9 @@
<ClInclude Include="AppLogic.h">
<DependentUpon>AppLogic.idl</DependentUpon>
</ClInclude>
<ClInclude Include="AdminWarningPlaceholder.h">
<DependentUpon>AdminWarningPlaceholder.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Toast.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
@@ -234,6 +240,9 @@
<ClCompile Include="AppLogic.cpp">
<DependentUpon>AppLogic.idl</DependentUpon>
</ClCompile>
<ClCompile Include="AdminWarningPlaceholder.cpp">
<DependentUpon>AdminWarningPlaceholder.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="Toast.cpp" />
</ItemGroup>
@@ -295,6 +304,10 @@
<DependentUpon>CommandPalette.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="AdminWarningPlaceholder.idl">
<DependentUpon>AdminWarningPlaceholder.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="FilteredCommand.idl" />
<Midl Include="EmptyStringVisibilityConverter.idl" />
</ItemGroup>

View File

@@ -17,6 +17,7 @@
#include "DebugTapConnection.h"
#include "SettingsTab.h"
#include "RenameWindowRequestedArgs.g.cpp"
#include "AdminWarningPlaceholder.h"
#include "../inc/WindowingBehavior.h"
#include <til/latch.h>
@@ -1415,21 +1416,24 @@ namespace winrt::TerminalApp::implementation
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
uint32_t realRowsToScroll;
if (rowsToScroll == nullptr)
if (const auto& termControl{ terminalTab->GetActiveTerminalControl() })
{
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
terminalTab->GetActiveTerminalControl().ViewHeight() :
_systemRowsToScroll;
uint32_t realRowsToScroll;
if (rowsToScroll == nullptr)
{
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
termControl.ViewHeight() :
_systemRowsToScroll;
}
else
{
// use the custom value specified in the command
realRowsToScroll = rowsToScroll.Value();
}
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
terminalTab->Scroll(scrollDelta);
}
else
{
// use the custom value specified in the command
realRowsToScroll = rowsToScroll.Value();
}
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
terminalTab->Scroll(scrollDelta);
}
}
@@ -1483,6 +1487,246 @@ namespace winrt::TerminalApp::implementation
return true;
}
// Function Description:
// - Returns true if this commandline is a commandline that we know is safe.
// Generally, this is true for any executables in system32. We can use
// this to bypass the elevated state check, because we're confident that
// executables in that path won't have been hijacked.
// - TECHNICALLY a user can take ownership of a file in system32 and
// replace it as the system administrator. You could say it's OK though
// because you'd already have to have had admin rights to mess that
// folder up or something.
// - Will attempt to resolve environment strings.
// - Will also manually allow commandlines as generated for the default WSL
// distros.
// - Will also trust %ProgramFiles%\Powershell\...\pwsh.exe paths, for
// PowerShell Core.
// Arguments:
// - commandLine: the command to check.
// Return Value (example):
// - C:\windows\system32\cmd.exe -> returns true
// - cmd.exe -> returns false
// - C:\windows\system32\cmd.exe /k echo sneaky sneak -> returns false
// - %SystemRoot%\System32\cmd.exe -> returns true
// - %SystemRoot%\System32\wsl.exe -d <distro name> -> returns true
bool TerminalPage::_isTrustedCommandline(std::wstring_view commandLine)
{
// use C++11 magic statics to make sure we only do this once.
static std::wstring systemDirectory = []() -> std::wstring {
// *** THIS IS A SINGLETON ***
static std::wstring sys32{};
if (FAILED(wil::GetSystemDirectoryW(sys32)))
{
// we couldn't look up where system32 is?? Then it's definitely not
// in System32
return {};
}
return sys32;
}();
if (systemDirectory.empty())
{
return false;
}
const std::wstring fullCommandline{
wil::ExpandEnvironmentStringsW<std::wstring>(commandLine.data())
};
if (fullCommandline.size() > systemDirectory.size())
{
// Get the first part of the executable path
const auto start = fullCommandline.substr(0, systemDirectory.size());
// Doing this as an ASCII only check might be wrong, but I'm
// guessing if system32 isn't at X:\windows\system32... this isn't
// the only thing that is going to be sad in Windows.
const auto pathEquals = til::equals_insensitive_ascii(start, systemDirectory);
if (pathEquals && std::filesystem::exists(std::filesystem::path{ fullCommandline }))
{
return true;
}
}
// We're explicitly not auto-allowing wsl.exe -d <distro name>. It's
// trivial to insert some malicious stuff into WSL, via .bash_profile,
// so we're not giving them the (y)
// But we do want to allow `pwsh.exe` profiles in the expected place to
// work.
const std::vector<std::filesystem::path> powershellCoreRoots
{
// Always look in "%LOCALAPPDATA%\Microsoft\WindowsApps", which is
// where the pwsh.exe execution alias lives.
{ wil::ExpandEnvironmentStringsW<std::wstring>(L"%LOCALAPPDATA%\\Microsoft\\WindowsApps") },
// Always look in "%ProgramFiles%\PowerShell"
{ wil::ExpandEnvironmentStringsW<std::wstring>(L"%ProgramFiles%\\PowerShell") },
#if defined(_M_AMD64) || defined(_M_ARM64) // No point in looking for WOW if we're not somewhere it exists
{ wil::ExpandEnvironmentStringsW<std::wstring>(L"%ProgramFiles(x86)%\\PowerShell") },
#endif
#if defined(_M_ARM64) // same with ARM
{
wil::ExpandEnvironmentStringsW<std::wstring>(L"%ProgramFiles(Arm)%\\PowerShell")
}
#endif
};
// Is the filename for this commandline `pwsh.exe`?
const std::filesystem::path exePath{ fullCommandline };
const auto endsWithPwsh{ exePath.filename() == L"pwsh.exe" };
// We'll also need to check the parent path, so make sure it has one here.
if (endsWithPwsh && exePath.has_parent_path())
{
const auto parentPath{ exePath.parent_path() };
for (const auto& pwshRoot : powershellCoreRoots)
{
// Does the commandline start with this root, and end with pwsh.exe?
const auto startsWithRoot{ til::starts_with(fullCommandline, pwshRoot.c_str()) };
// Is either the immediate parent, or the grandparent, this root exactly?
//
// We need to check the grandparent for the
// `%ProgramFiles%\\PowerShell\\7\\pwsh.exe` case.
const auto parentIsCorrect = (parentPath == pwshRoot) ||
(parentPath.has_parent_path() && parentPath.parent_path() == pwshRoot);
if (startsWithRoot && parentIsCorrect)
{
return true;
}
}
}
return false;
}
// Method Description:
// - For a given commandline, determines if we should prompt the user for
// approval. We only do this check when elevated. This will check the
// AllowedCommandlines in `elevated-state.json`, to see if the commandline
// already exists in that list.
// Arguments:
// - cmdline: The commandline to check
// Return Value:
// - true if we should prompt the user for approval.
bool TerminalPage::_shouldPromptForCommandline(const winrt::hstring& cmdline) const
{
// NOTE: For debugging purposes, changing this to `true || IsElevated()`
// is a handy way of forcing the elevation logic, even when unelevated.
if (IsElevated())
{
// If the cmdline is EXACTLY an executable in
// `C:\WINDOWS\System32`, then ignore this check.
if (_isTrustedCommandline(cmdline))
{
return false;
}
if (const auto& allowedCommandlines{ ApplicationState::SharedInstance().AllowedCommandlines() })
{
for (const auto& approved : allowedCommandlines)
{
if (approved == cmdline)
{
return false;
}
}
}
return true;
}
return false;
}
void TerminalPage::_adminWarningPrimaryClicked(const TerminalApp::AdminWarningPlaceholder& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
auto warningControl{ winrt::get_self<AdminWarningPlaceholder>(sender) };
const auto& cmdline{ warningControl->Commandline() };
// Look through the tabs and panes to look for us. Whichever pane had us
// as content - replace their content with the TermControl we were
// holding on to.
for (const auto& tab : _tabs)
{
if (const auto& tabImpl{ _GetTerminalTabImpl(tab) })
{
tabImpl->GetRootPane()->WalkTree([warningControl, cmdline, tabImpl](std::shared_ptr<Pane> pane) -> bool {
const auto& projectedWarningControl{ pane->GetUserControl().try_as<TerminalApp::AdminWarningPlaceholder>() };
// If it was a warning control, then get our implementation
// type out of it.
if (const auto& otherWarning{ winrt::get_self<AdminWarningPlaceholder>(projectedWarningControl) })
{
// This pane had a warning in it.
// Was it a warning for the same commandline that we
// just approved?
if (otherWarning->Commandline() == cmdline)
{
// Go ahead and allow them. Swap the control into
// the pane, which will initialize and start it.
tabImpl->ReplaceControl(pane, otherWarning->Control());
}
// Don't return true here. We want to make sure to check
// all the panes for the same commandline we just
// approved.
}
// return false so we make sure to iterate on every leaf.
return false;
});
}
}
// Update the list of approved commandlines.
auto allowedCommandlines{ ApplicationState::SharedInstance().AllowedCommandlines() };
if (!allowedCommandlines)
{
allowedCommandlines = winrt::single_threaded_vector<winrt::hstring>();
}
// But of course, we don't need to add this commandline if it's already
// in the list of approved commandlines.
bool foundCopy = false;
for (const auto& approved : allowedCommandlines)
{
if (approved == cmdline)
{
foundCopy = true;
break;
}
}
if (!foundCopy)
{
allowedCommandlines.Append(cmdline);
}
ApplicationState::SharedInstance().AllowedCommandlines(allowedCommandlines);
}
void TerminalPage::_adminWarningCancelClicked(const TerminalApp::AdminWarningPlaceholder& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
auto warningControl{ winrt::get_self<AdminWarningPlaceholder>(sender) };
for (const auto& tab : _tabs)
{
if (const auto& tabImpl{ _GetTerminalTabImpl(tab) })
{
tabImpl->GetRootPane()->WalkTree([warningControl](std::shared_ptr<Pane> pane) -> bool {
if (pane->GetUserControl() == *warningControl)
{
pane->Close();
return true;
}
// We're not going to auto-close all the other panes with
// the same commandline warning, akin to what we're doing in
// the approve handler. If they want to reject one pane, but
// accept the next one, that's okay.
return false;
});
}
}
}
// Method Description:
// - Split the focused pane either horizontally or vertically, and place the
// given pane accordingly in the tree
@@ -1852,8 +2096,10 @@ namespace winrt::TerminalApp::implementation
if (warnMultiLine)
{
const auto focusedTab = _GetFocusedTabImpl();
const auto& termControl{ focusedTab->GetActiveTerminalControl() };
// Do not warn about multi line pasting if the current tab has bracketed paste enabled.
warnMultiLine = warnMultiLine && !focusedTab->GetActiveTerminalControl().BracketedPasteEnabled();
warnMultiLine = warnMultiLine &&
(termControl && !termControl.BracketedPasteEnabled());
}
// We have to initialize the dialog here to be able to change the text of the text block within it
@@ -2161,11 +2407,14 @@ namespace winrt::TerminalApp::implementation
// 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)
if (const auto& control{ focusedTab->GetActiveTerminalControl() })
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
const auto workingDirectory = control.WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
}
}
}
}
@@ -2199,7 +2448,21 @@ namespace winrt::TerminalApp::implementation
const auto control = _InitControl(controlSettings, connection);
_RegisterTerminalEvents(control);
auto resultPane = std::make_shared<Pane>(profile, control);
WUX::Controls::UserControl controlToAdd{ control };
// Check if we should warn the user about running a new unelevated
// commandline.
const auto& cmdline{ controlSettings.DefaultSettings().Commandline() };
const auto doAdminWarning{ _shouldPromptForCommandline(cmdline) };
if (doAdminWarning)
{
auto warningControl{ winrt::make_self<implementation::AdminWarningPlaceholder>(control, cmdline) };
warningControl->PrimaryButtonClicked({ get_weak(), &TerminalPage::_adminWarningPrimaryClicked });
warningControl->CancelButtonClicked({ get_weak(), &TerminalPage::_adminWarningCancelClicked });
controlToAdd = *warningControl;
}
auto resultPane = std::make_shared<Pane>(profile, controlToAdd);
if (debugConnection) // this will only be set if global debugging is on and tap is active
{
@@ -2220,6 +2483,17 @@ namespace winrt::TerminalApp::implementation
original->SetActive();
}
if (doAdminWarning)
{
// We know this is safe - we literally just added the
// AdminWarningPlaceholder as the controlToAdd like 20 lines up.
//
// Focus the warning here. The LayoutUpdated within the dialog
// itself isn't good enough. That, for some reason, fires _before_
// the dialog is in the UI tree, which is useless for us.
controlToAdd.try_as<implementation::AdminWarningPlaceholder>()->FocusOnLaunch();
}
return resultPane;
}

View File

@@ -19,6 +19,7 @@ namespace TerminalAppLocalTests
{
class TabTests;
class SettingsTests;
class TrustCommandlineTests;
};
namespace winrt::TerminalApp::implementation
@@ -207,6 +208,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseReadOnlyDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowMultiLinePasteWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowLargePasteWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCommandlineApproveWarning();
void _CreateNewTabFlyout();
void _OpenNewTabDropdown();
@@ -403,6 +405,12 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept;
bool _shouldPromptForCommandline(const winrt::hstring& cmdline) const;
void _adminWarningPrimaryClicked(const winrt::TerminalApp::AdminWarningPlaceholder& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& args);
void _adminWarningCancelClicked(const winrt::TerminalApp::AdminWarningPlaceholder& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& args);
winrt::fire_and_forget _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
@@ -410,6 +418,7 @@ namespace winrt::TerminalApp::implementation
void _SetAsDefaultOpenSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static bool _isTrustedCommandline(std::wstring_view commandLine);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
@@ -420,6 +429,7 @@ namespace winrt::TerminalApp::implementation
friend class TerminalAppLocalTests::TabTests;
friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::TrustCommandlineTests;
};
}

View File

@@ -426,7 +426,10 @@ namespace winrt::TerminalApp::implementation
winrt::fire_and_forget TerminalTab::Scroll(const int delta)
{
auto control = GetActiveTerminalControl();
if (!control)
{
co_return;
}
co_await winrt::resume_foreground(control.Dispatcher());
const auto currentOffset = control.ScrollOffset();
@@ -511,7 +514,11 @@ namespace winrt::TerminalApp::implementation
if (p->_IsLeaf())
{
p->Id(_nextPaneId);
_AttachEventHandlersToControl(p->Id().value(), p->_control);
if (auto termControl{ p->_control.try_as<TermControl>() })
{
_AttachEventHandlersToControl(p->Id().value(), termControl);
}
_nextPaneId++;
}
return false;
@@ -856,6 +863,10 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::_AttachEventHandlersToControl(const uint32_t paneId, const TermControl& control)
{
if (!control)
{
return;
}
auto weakThis{ get_weak() };
auto dispatcher = TabViewItem().Dispatcher();
ControlEventTokens events{};
@@ -1744,6 +1755,19 @@ namespace winrt::TerminalApp::implementation
return Title();
}
void TerminalTab::ReplaceControl(std::shared_ptr<Pane> pane, const Controls::UserControl& control)
{
pane->ReplaceControl(control);
if (auto termControl{ pane->_control.try_as<TermControl>() })
{
_AttachEventHandlersToControl(pane->Id().value(), termControl);
}
// Update the title manually.
UpdateTitle();
}
DEFINE_EVENT(TerminalTab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
DEFINE_EVENT(TerminalTab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>);

View File

@@ -93,6 +93,9 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> GetRootPane() const { return _rootPane; }
void ReplaceControl(std::shared_ptr<Pane> pane,
const winrt::Windows::UI::Xaml::Controls::UserControl& control);
winrt::TerminalApp::TerminalTabStatus TabStatus()
{
return _tabStatus;

View File

@@ -2645,4 +2645,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return _core.ReadEntireBuffer();
}
Media::Brush TermControl::BackgroundBrush()
{
return RootGrid().Background();
}
}

View File

@@ -105,6 +105,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
hstring ReadEntireBuffer() const;
Windows::UI::Xaml::Media::Brush BackgroundBrush();
// -------------------------------- WinRT Events ---------------------------------
// clang-format off
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);

View File

@@ -71,5 +71,7 @@ namespace Microsoft.Terminal.Control
void ToggleReadOnly();
String ReadEntireBuffer();
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
}
}