Compare commits

..

27 Commits

Author SHA1 Message Date
Dustin Howett
4db5e0eefd Merge remote-tracking branch 'openconsole/inbox' into release-1.19 2024-02-26 11:22:49 -06:00
Leonard Hecker
0ec73b1a6e Fix an apparent x86 miscompilation on MSVC 19.38 (#16742)
There's an apparent miscompilation of `dynamic_bitset` on x86 with
MSVC 19.38, where the following code:
```cpp
dynamic_bitset<uint64_t> bits(80 * 24, 0);
bits.set(0, 3 * 80, true);
```

is expected to set the first 3.75 blocks to 1 which should produce
the following blocks:
```
0xffffffffffffffff
0xffffffffffffffff
0xffffffffffffffff
0x0000ffffffffffff
```

but it actually produces:
```
0xffffffffffffffff
0x00000000ffffffff
0xffffffffffffffff
0x0000ffffffffffff
```

The weird thing here is that this only happens if `til::bitmap`
uses a `dynamic_bitset<uint64_t>`. As soon as it uses `<uint32_t>`
any other instantiation of `<uint64_t>` is magically fixed.

Conclusion: Use `size_t` until we know what's going on.
Last known good CL version: 14.37.32822
Current broken CL version: 14.38.33130

## Validation Steps Performed

The following test completes successfully again:
```cpp
til::bitmap map{ { 80, 24 } };
map.translate({ 0, 3 }, true);
VERIFY_ARE_EQUAL(3u, map.runs().size());
```

(cherry picked from commit d3ec47a7fc)
Service-Card-Id: 91885583
Service-Version: 1.19
2024-02-21 11:54:50 -06:00
Leonard Hecker
78da9bd965 COOKED_READ: Fix tab not erasing the prompt (#16718)
Write "<command that doesn't exist> foo" in cmd.exe, move yours cursor
past the <command> and press tab. The "foo" will still be there but
will be inaccessible. This commit fixes the issue. As far as I can
tell, this never worked in any conhost version ever.

Closes #16704

(cherry picked from commit 5e9f223a6c)
Service-Card-Id: 91851714
Service-Version: 1.19
2024-02-21 11:54:06 -06:00
Dustin Howett
23580749a4 Merged PR 10310193: [Git2Git] Merged PR 10300003: conhost: extract icons ourselves to remove shell32 dependency
Changes recently landed in `ge_release_we_adept_dev` that result in
conhost loading `Windows.Storage.dll` during startup, rather than
`shell32`. This causes a memory usage regression.

The only thing we need from `shell32` during startup is
`ExtractIconExW`. Fortunately, that function is relatively simple and
it relies only on things from `user32` (and one thing from `comctl32`).

Enclosed herein is an implementation of `ExtractIconExW` that is tuned
for conhost's specific use case and tidied up.

Related work items: MSFT-48947348

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/ge_release_we_adept_dev c54c102a362c3dbc7a64cc148b45b993b4154ead
2024-02-19 14:58:20 +00:00
Dustin Howett
151da764ef Migrate OSS up to 438571bd7 (v1.19.10301.0+) 2024-02-01 17:55:56 -06:00
Leonard Hecker
438571bd7f Restore support for pasting files (#16634)
TIL: You could Ctrl+V files into Windows Terminal and here I am,
always opening the context menu and selecting "Copy as path"... smh

This restores the support by adding a very rudimentary HDROP handler.
The flip side of the regression is that I learned about this and so
conhost also gets this now, because why not!

Closes #16627

* Single files can be pasted in WT and conhost 

(cherry picked from commit ef96e225da)
Service-Card-Id: 91727725
Service-Version: 1.19
2024-02-01 17:54:50 -06:00
Leonard Hecker
01868978b3 Fix a bug caused by #16592 (#16624)
#16592 passes the return value of `GetEnvironmentStringsW` directly
to the `hstring` constructor even though the former returns a
double-null terminated string and the latter expects a regular one.

This PR fixes the issue by using a basic strlen() loop to compute
the length ourselves. It's still theoretically beneficial over
the previous code, but now it's rather bitter since the code isn't
particularly short anymore and so the biggest benefit is gone.

Closes #16623

## Validation Steps Performed
* Validated the `env` string in a debugger 
  It's 1 character shorter than the old `til::env` string.
  That's fine however, since any `HSTRING` is always null-terminated
  anyways and so we get an extra null-terminator for free.
* `wt powershell` works 

(cherry picked from commit c669afe2a0)
Service-Card-Id: 91719862
Service-Version: 1.19
2024-01-30 18:25:26 -06:00
Dustin L. Howett
26d35c3ac5 build: remove symbols' dependency on the Package phase (#16625)
Due to things outside our control, sometimes the Package phase fails
when VPack publication is enabled. Because of this, symbols won't be
published. We still want these builds to be considered "golden" and we
are still shipping them, so we *must* publish symbols.

(cherry picked from commit bcca7aac1b)
Service-Card-Id: 91719595
Service-Version: 1.19
2024-01-30 18:25:25 -06:00
Leonard Hecker
add1632d63 Fix conhost clipboard handling bugs (#16618)
conhost has 2 bugs related to clipboard handling:
* Missing retry on `OpenClipboard`: When copying to the clipboard
  explorer.exe is very eager to open the clipboard and peek into it.
  I'm not sure why it happens, but I can see `CFSDropTarget` in the
  call stack. It uses COM RPC and so this takes ~20ms every time.
  That breaks conhost's clipboard randomly during `ConsoleBench`.
  During non-benchmarks I expect this to break during RDP.
* Missing null-terminator check during paste: `CF_UNICODETEXT` is
  documented to be a null-terminated string, which conhost v2
  failed to handle as it relied entirely on `GlobalSize`.

Additionally, this changeset simplifies the `HGLOBAL` code slightly
by adding `_copyToClipboard` to abstract it away.

* `ConsoleBench` (#16453) doesn't fail randomly anymore 

(cherry picked from commit 86c30bd)
2024-01-30 07:52:11 -08:00
Leonard Hecker
bc48eda022 Reset _wrapForced when erasing scrollback (#16610)
#15541 changed `AdaptDispatch::_FillRect` which caused it to not affect
the `ROW::_wrapForced` flag anymore. This change in behavior was not
noticeable as `TextBuffer::GetLastNonSpaceCharacter` had a bug where
rows of only whitespace text would always be treated as empty.
This would then affect `AdaptDispatch::_EraseAll` to accidentally
correctly guess the last row with text despite the `_FillRect` change.

#15701 then fixed `GetLastNonSpaceCharacter` indirectly by fixing
`ROW::MeasureRight` which now made the previous change apparent.
`_EraseAll` would now guess the last row of text incorrectly,
because it would find the rows that `_FillRect` cleared but still
had `_wrapForced` set to `true`.

This PR fixes the issue by replacing the `_FillRect` usage to clear
rows with direct calls to `ROW::Reset()`. In the future this could be
extended by also `MEM_DECOMMIT`ing the now unused underlying memory.

Closes #16603

## Validation Steps Performed
* Enter WSL and resize the window to <40 columns
* Execute
  ```sh
  cd /bin
  ls -la
  printf "\e[3J"
  ls -la
  printf "\e[3J"
  printf "\e[2J"
  ```
* Only one viewport-height-many lines of whitespace exist between the
  current prompt line and the previous scrollback contents 

(cherry picked from commit 5f71cf3e94)
Service-Card-Id: 91707937
Service-Version: 1.19
2024-01-29 17:12:27 -06:00
Leonard Hecker
29895e1c2d Improve conhost's scrolling performance (#16333)
`EnableScrollbar()` and especially `SetScrollInfo()` are prohibitively
expensive functions nowadays. This improves throughput of good old
`type` in cmd.exe by ~10x, by briefly releasing the console lock.

## Validation Steps Performed
* `type`ing a file in `cmd` is as fast while the window is scrolling
  as it is while it isn't scrolling 
* Scrollbar pops in and out when scroll-forward is disabled 

(cherry picked from commit 71a6f26e6e)
Service-Card-Id: 91152166
Service-Version: 1.19
2024-01-29 17:12:26 -06:00
Leonard Hecker
04edb112ea Pump the message queue on frozen windows (#16588)
This changeset ensures that the message queue of frozen windows is
always being serviced. This should ensure that it won't fill up and
lead to deadlocks, freezes, or similar. I've tried _a lot_ of different
approaches before settling on this one. Introducing a custom `WM_APP`
message has the benefit of being the least intrusive to the existing
code base.

The approach that I would have favored the most would be to never
destroy the `AppHost` instance in the first place, as I imagined that
this would be more robust in general and resolve other (rare) bugs.
However, I found that this requires rewriting some substantial parts
of the code base around `AppHost` and it could be something that may
be of interest in the future.

Closes #16332
Depends on #16587 and #16575

(cherry picked from commit 5d2fa4782f)
Service-Card-Id: 91642479
Service-Version: 1.19
2024-01-29 16:47:54 -06:00
Mike Griese
9c10575c73 Don't end the current mark, if we get one of the same kind (#16107)
If you're already in the "output" state, then an app requesting an
"output" mark probably shouldn't end the current mark and start a new
one. It should just keep on keepin' on.

The decision to end the previous one was arbitrary in the first place,
so let's arbitrarily change it back.

Especially noticable if you hit <kbd>Enter</kbd> during a command,
because the auto-mark prompt work will do a CommandEnd, so long-running
commands will get broken into multiple marks 🥲

(cherry picked from commit 0144cdd7bc)
Service-Card-Id: 91707294
Service-Version: 1.19
2024-01-29 16:47:53 -06:00
Dustin L. Howett
7e46fa35f7 Migrate OSS up to 5575187b2 (1.19-pre, DECST8C, font) 2024-01-29 14:08:57 -06:00
Leonard Hecker
5575187b26 Add missing TraceLoggingRegister calls (VT ONLY) (#16467)
17cc109 and e9de646 both made the same mistake: When cleaning up our
telemetry code they also removed the calls to `TraceLoggingRegister`
which also broke regular tracing. Windows Defender in particular uses
the "CookedRead" event to monitor for malicious shell commands.

This doesn't fix it the "right way", because destructors of statics
aren't executed when DLLs are unloaded. But I felt like that this is
fine because we have way more statics than that in conhost land,
all of which have the same kind of issue.

(cherry picked from commit a65d5f321f)
Service-Card-Id: 91337330
Service-Version: 1.19
2024-01-29 14:05:55 -06:00
Leonard Hecker
48a6d92255 Fix font preview for conhost (#16324)
After exiting the main loop in this function the invariant
`nFont <= NumberOfFonts` still holds true. Additionally,
preceding this removed code is this (paraphrased):
```cpp
if (nFont < NumberOfFonts) {
    RtlMoveMemory(...);
}
```
It ensures that the given slot `nFont` is always unoccupied by moving
it and all following items upwards if needed. As such, the call to
`DeleteObject` is always incorrect, as the slot is always "empty",
but may contain a copy of the previous occupant due to the `memmove`.

This regressed in 154ac2b.

Closes #16297

## Validation Steps Performed
* All fonts have a unique look in the preview panel 

(cherry picked from commit 35240f263e)
Service-Card-Id: 91120871
Service-Version: 1.19
2024-01-29 14:04:05 -06:00
Dustin L. Howett
e727aaf679 Merge remote-tracking branch 'origin/inbox' into release-1.19 2024-01-29 13:52:43 -06:00
Mike Griese
98146c9d1b Use TerminateProcess to exit early (#16575)
Closes MSFT:46744208

BODGY: If the emperor is being dtor'd, it's because we've gone past the
end of main, and released the ref in main. Then we might run into an
edge case where main releases it's ref to the emperor, but one of the
window threads might be in the process of exiting, and still holding a
strong ref to the emperor. In that case, we can actually end up with
the _window thread_ being the last reference, and calling App::Close
on that thread will crash us with a E_WRONG_THREAD.

This fixes the issue by calling `TerminateProcess` explicitly.

How validated: The ES team manually ran the test pass this was
crashing in a hundred times to make sure this actually fixed it.

Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
(cherry picked from commit 0d47c862c2)
Service-Card-Id: 91642489
Service-Version: 1.19
2024-01-29 13:09:24 -06:00
Leonard Hecker
e6ac014fc8 Simplify WindowEmperor::HandleCommandlineArgs (#16592)
This simplifies the function in two ways:
* Passing `nCmdShow` from `wWinMain` alleviates the need to interpret
  the return value of `GetStartupInfoW`.
* `til::env::from_current_environment()` calls `GetEnvironmentStringsW`
  to get the environment variables, while `to_string()` turns it back.
  Calling the latter directly alleviates the need for this round-trip.

(cherry picked from commit a39ac598cd)
Service-Card-Id: 91643115
Service-Version: 1.19
2024-01-29 13:09:22 -06:00
glenrgordon
b08dc61a9c Eliminate two memory leaks (#16597)
In WindowsTerminal, there was a leak of a BSTR with every call to
ITextRangeProvider::GetText, and a failure to call VariantClear in
ITextRange::GetAttributeValue when the value stored in the variant is
VT_BSTR. These were fixed by switching to wil::unique_bstr and
wil::unique_variant.

(cherry picked from commit da99d892f4)
Service-Card-Id: 91631736
Service-Version: 1.19
2024-01-25 16:46:02 -06:00
James Holderness
ba6f1e905d Add support for the DECST8C escape sequence (#16534)
## Summary of the Pull Request

This PR adds support for the `DECST8C` escape sequence, which resets the
tab stops to every 8 columns.

## Detailed Description of the Pull Request / Additional comments

This is actually a private parameter variant of the ANSI `CTC` sequence
(Cursor Tabulation Control), which accepts a selective parameter which
specifies the type of tab operation to be performed. But the DEC variant
only defines a single parameter value (5), which resets all tab stops.
It also considers an omitted parameter to be the equivalent of 5, so we
support that too.

## Validation Steps Performed

I've extended the existing tab stop tests in `ScreenBufferTests` with
some basic coverage of this sequence.

I've also manually verified that the `DECTABSR` script in #14984 now
passes the `DECST8C` portion of the test.

## PR Checklist
- [x] Closes #16533
- [x] Tests added/passed

(cherry picked from commit f5898886be)
Service-Card-Id: 91631721
Service-Version: 1.19
2024-01-25 16:46:01 -06:00
Dustin L. Howett
bc452c61dc Revert "Add magic incantation to tell Store we support Server" (#16594)
This reverts commit abab8705fe.

It went badly, as you might imagine.

(cherry picked from commit fe65d9ac8f)
Service-Card-Id: 91620326
Service-Version: 1.19
2024-01-25 16:46:00 -06:00
James Holderness
204794f9f3 Add support for more DSR queries. (#16525)
## Summary of the Pull Request

This PR adds support for more Device Status Report (`DSR`) queries,
specifically:

* Printer Status (`DSR ?15`)
* User Defined Keys (`DSR ?25`)
* Keyboard Status (`DSR ?26`)
* Locator Status (`DSR ?55`)
* Locator Identity (`DSR ?56`)
* Data Integrity (`DSR ?75`)
* Multiple Session Status (`DSR ?85`)

## Detailed Description of the Pull Request / Additional comments

For most of these, we just need to return a `DSR` sequence indicating
that the functionality isn't supported.

* `DSR ?13` indicates that a printer isn't connected.
* `DSR ?23` indicates the UDK extension isn't supported.
* `DSR ?53` indicates that a locator device isn't connected
* `DSR ?57;0` indicates the locator type is unknown or not connected.
* `DSR ?83` indicates that multiple sessions aren't supported.

For the keyboard, we report `DSR ?27;0;0;5`, indicating a PC keyboard
(the `5` parameter), a "ready" status (the second `0` parameter), and an
unknown language (the first `0` parameter). In the long term, there may
be some value in identifying the actual keyboard language, but for now
this should be good enough.

The data integrity report was originally used to detect communication
errors between the terminal and host, but that's not really applicable
for modern terminals, so we always just report `DSR ?70`, indicating
that there are no errors.

## Validation Steps Performed

I've added some more adapter tests and output engine tests covering the
new reports.

## PR Checklist
- [x] Closes #16518
- [x] Tests added/passed

(cherry picked from commit 6c192d15be)
Service-Card-Id: 91631713
Service-Version: 1.19
2024-01-25 16:45:59 -06:00
Leonard Hecker
4902b342ef Avoid timer ticks on frozen windows (#16587)
At the time of writing, closing the last tab of a window inexplicably
doesn't lead to the destruction of the remaining TermControl instance.
On top of that, on Win10 we don't destroy window threads due to bugs in
DesktopWindowXamlSource. In other words, we leak TermControl instances.

Additionally, the XAML timer class is "self-referential".
Releasing all references to an instance will not stop the timer.
Only calling Stop() explicitly will achieve that.

The result is that the message loop of a frozen window thread has so
far received 1-2 messages per second due to the blink timer not being
stopped. This may have filled the message queue and lead to bugs as
described in #16332 where keyboard input stopped working.

(cherry picked from commit 521a300c17)
Service-Card-Id: 91642474
Service-Version: 1.19
2024-01-25 16:45:58 -06:00
Carlos Zamora
03aa8a6231 Update SUI Color Scheme colors' AutoProp.Name and ToolTip (#16544)
In the Settings UI's Color Scheme page (where you edit the color scheme itself), update the color chip buttons to include the RGB value in the tooltip and screen reader announcements.

Closes #15985
Closes #15983

## Validation Steps Performed
Tooltip and screen reader announcement is updated on launch and when a new value is selected.

(cherry picked from commit 057183b651)
Service-Card-Id: 91642735
Service-Version: 1.19
2024-01-25 16:45:56 -06:00
James Holderness
10fb5448cc Change the SUB control glyph to U+2426 (#16559)
Up to now we've using `U+2E2E` (reverse question mark) to represent the
`SUB` control glyph. This PR changes the glyph to `U+2426` (substitute
form two), which is also rendered as a reverse question mark, but is
more semantically correct.

The original `SUB` control rendering was implemented in PR #15075.

I've manually confirmed that `printf "\x1A"` is now shown as a reverse
question mark in OpenConsole when using the Cascadia Code font. That
would not previously have worked, because `U+2E2E` is not supported by
Cascadia Code.

Closes #16558

(cherry picked from commit 92f9ff948b)
Service-Card-Id: 91559316
Service-Version: 1.19
2024-01-22 16:50:25 -06:00
Dustin L. Howett
a24afcd1e6 Remove EDP auditing completely (#16460)
This pull request started out very differently. I was going to move all
the EDP code from the internal `conint` project into the public, because
EDP is [fully documented]!

Well, it doesn't have any headers in the SDK.

Or import libraries.

And it's got a deprecation notice:

> [!NOTE]
> Starting in July 2022, Microsoft is deprecating Windows Information
> Protection (WIP) and the APIs that support WIP. Microsoft will
continue
> to support WIP on supported versions of Windows. New versions of
Windows
> won't include new capabilities for WIP, and it won't be supported in
> future versions of Windows.

So I'm blasting it out the airlock instead.

[fully documented]:
https://learn.microsoft.com/en-us/windows/win32/devnotes/windows-information-protection-api

(cherry picked from commit c4c06dadad)
Service-Card-Id: 91327265
Service-Version: 1.19
2024-01-22 16:50:24 -06:00
217 changed files with 7467 additions and 6186 deletions

View File

@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"XamlStyler.Console": {
"version": "3.2311.2",
"version": "3.2206.4",
"commands": [
"xstyler"
]

View File

@@ -6,6 +6,8 @@
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
:warning: The command is written for posix shells. If it doesn't work for you, you can manually _add_ (one word per line) / _remove_ items to `expect.txt` and the `excludes.txt` files.
If the listed items are:
* ... **misspelled**, then please *correct* them instead of using the command.
@@ -34,9 +36,7 @@ https://www.regexplanet.com/advanced/perl/) yours before committing to verify it
* well-formed pattern.
If you can write a [pattern](
https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
) that would match it,
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
try adding it to the `patterns.txt` file.
Patterns are Perl 5 Regular Expressions - you can [test](

View File

@@ -55,7 +55,6 @@ hyperlinks
iconify
img
inlined
issuetitle
It'd
kje
libfuzzer
@@ -96,11 +95,9 @@ rlig
runtimes
servicebus
shcha
similaritytolerance
slnt
Sos
ssh
sustainability
stakeholders
sxn
timeline
@@ -124,7 +121,6 @@ walkthroughs
We'd
westus
wildcards
workarounds
XBox
YBox
yeru

View File

@@ -210,7 +210,6 @@ tlg
TME
tmp
tmpdir
tokeninfo
tolower
toupper
TRACKMOUSEEVENT

View File

@@ -6,7 +6,6 @@ bhoj
Bhojwani
Bluloco
carlos
craigloewen
dhowett
Diviness
dsafa

View File

@@ -1,37 +1,23 @@
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
# marker to ignore all code on line
^.*\bno-spell-check(?:-line|)(?:\s.*|)$
# https://cspell.org/configuration/document-settings/
# cspell inline
^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b
# 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}\.\.[0-9a-z]{7,40}
# file permissions
['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
# css url wrappings
\burl\([^)]+\)
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:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
# data url in quotes
([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# data url
data:[-a-zA-Z=;:/0-9+]*,\S*
# https/http/file urls
(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
@@ -49,9 +35,6 @@ magnet:[?=:\w]+
# asciinema
\basciinema\.org/a/[0-9a-zA-Z]+
# asciinema v2
^\[\d+\.\d+, "[io]", ".*"\]$
# apple
\bdeveloper\.apple\.com/[-\w?=/]+
# Apple music
@@ -106,7 +89,7 @@ vpc-\w+
# Google Drive
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
# Google Groups
\bgroups\.google\.com(?:/[a-z]+/(?:#!|)[^/\s"]+)*
\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
@@ -134,8 +117,6 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# GitHub SHAs
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
# GitHub SHA refs
\[([0-9a-f]+)\]\(https://(?:www\.|)github.com/[-\w]+/[-\w]+/commit/\g{-1}[0-9a-f]*
# GitHub wiki
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
# githubusercontent
@@ -147,9 +128,9 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
# git.io
\bgit\.io/[0-9a-zA-Z]+
# GitHub JSON
"node_id": "[-a-zA-Z=;:/0-9+_]*"
"node_id": "[-a-zA-Z=;:/0-9+]*"
# Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+/?\)
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
# GHSA
GHSA(?:-[0-9a-z]{4}){3}
@@ -162,8 +143,8 @@ GHSA(?:-[0-9a-z]{4}){3}
# GitLab commits
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
# binance
accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
# 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]+
@@ -299,9 +280,9 @@ slack://[a-zA-Z0-9?&=]+
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
# ipfs protocol
ipfs://[0-9a-zA-Z]{3,}
ipfs://[0-9a-z]*
# ipfs url
/ipfs/[0-9a-zA-Z]{3,}
/ipfs/[0-9a-z]*
# w3
\bw3\.org/[-0-9a-zA-Z/#.]+
@@ -378,33 +359,22 @@ ipfs://[0-9a-zA-Z]{3,}
# tinyurl
\btinyurl\.com/\w+
# codepen
\bcodepen\.io/[\w/]+
# registry.npmjs.org
\bregistry\.npmjs\.org/(?:@[^/"']+/|)[^/"']+/-/[-\w@.]+
# getopts
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# URL escaped characters
\%[0-9A-F][A-F](?=[A-Za-z])
# lower URL escaped characters
\%[0-9a-f][a-f](?=[a-z]{2,})
\%[0-9A-F][A-F]
# IPv6
#\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
# c99 hex digits (not the full format, just one I've seen)
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
# Punycode
\bxn--[-0-9a-z]+
# sha
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture
(\\?['"]|&quot;)[0-9a-f]{40,}\g{-1}
(['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
# hex in url queries
@@ -419,21 +389,18 @@ sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# Well known gpg keys
.well-known/openpgpkey/[\w./]+
# pki
-----BEGIN.*-----END
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# integrity
integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
# https://www.gnu.org/software/groff/manual/groff.html
# man troff content
\\f[BCIPR]
# '/"
\\\([ad]q
# '
\\\(aq
# .desktop mime types
^MimeTypes?=.*$
@@ -442,33 +409,21 @@ integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
# Localized .desktop content
Name\[[^\]]+\]=.*
# IServiceProvider / isAThing
\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# crypt
(['"])\$2[ayb]\$.{56}\g{-1}
"\$2[ayb]\$.{56}"
# scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+
# go.sum
\bh1:\S+
# scala modules
("[^"]+"\s*%%?\s*){2,3}"[^"]+"
# Input to GitHub JSON
content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
content: "[-a-zA-Z=;:/0-9+]*="
# This does not cover multiline strings, if your repository has them,
# you'll want to remove the `(?=.*?")` suffix.
# The `(?=.*?")` suffix should limit the false positives rate
# printf
#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA]|p)(?=[a-zA-Z]{2,}))(?=[_a-zA-Z]+\b)(?!%)(?=.*?['"])
# Python string prefix / binary prefix
# 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,})
(?<!')\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]+
@@ -484,35 +439,16 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
# javascript replace regex
\.replace\(/[^/\s"]*/[gim]*\s*,
# assign regex
= /[^*]*?(?:[a-z]{3,}|[A-Z]{3,}|[A-Z][a-z]{2,}).*/
# perl regex test
[!=]~ (?:/.*/|m\{.*?\}|m<.*?>|m([|!/@#,;']).*?\g{-1})
# perl qr regex
(?<!\$)\bqr(?:\{.*?\}|<.*?>|\(.*?\)|([|!/@#,;']).*?\g{-1})
# Go regular expressions
regexp?\.MustCompile\(`[^`]*`\)
# regex choice
\(\?:[^)]+\|[^)]+\)
# proto
^\s*(\w+)\s\g{-1} =
# sed regular expressions
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
# node packages
(["'])\@[^/'" ]+/[^/'" ]+\g{-1}
# go install
go install(?:\s+[a-z]+\.[-@\w/.]+)+
# jetbrains schema https://youtrack.jetbrains.com/issue/RSRP-489571
urn:shemas-jetbrains-com
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
@@ -524,47 +460,19 @@ urn:shemas-jetbrains-com
-[0-9a-f]{10}-\w{5}\s
# posthog secrets
([`'"])phc_[^"',]+\g{-1}
posthog\.init\((['"])phc_[^"',]+\g{-1},
# xcode
# xcodeproject scenes
(?:Controller|destination|ID|id)="\w{3}-\w{2}-\w{3}"
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches
customObjectInstantitationMethod
# configure flags
.* \| --\w{2,}.*?(?=\w+\s\w+)
# font awesome classes
\.fa-[-a-z0-9]+
# bearer auth
(['"])Bear[e][r] .*?\g{-1}
# basic auth
(['"])Basic [-a-zA-Z=;:/0-9+]{3,}\g{-1}
# base64 encoded content
#([`'"])[-a-zA-Z=;:/0-9+]+=\g{-1}
# base64 encoded content in xml/sgml
>[-a-zA-Z=;:/0-9+]+=</
# base64 encoded content, possibly wrapped in mime
#(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$)
# encoded-word
=\?[-a-zA-Z0-9"*%]+\?[BQ]\?[^?]{0,75}\?=
# Time Zones
\b(?:Africa|Atlantic|America|Antarctica|Asia|Australia|Europe|Indian|Pacific)(?:/\w+)+
# linux kernel info
^(?:bugs|flags|Features)\s+:.*
# systemd mode
systemd.*?running in system mode \([-+].*\)$
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
@@ -575,62 +483,32 @@ systemd.*?running in system mode \([-+].*\)$
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
# highlighted letters
\[[A-Z]\][a-z]+
[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 (check-spelling <= 0.0.21)
#\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# latex (check-spelling >= 0.0.22)
\\\w{2,}\{
# eslint
"varsIgnorePattern": ".+"
# Windows short paths
[/\\][^/\\]{5,6}~\d{1,2}[/\\]
# in check-spelling@v0.0.22+, printf markers aren't automatically consumed
# printf markers
#(?<!\\)\\[nrt](?=[a-z]{2,})
# alternate markers if you run into latex and friends
#(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*['"`])
# apache
a2(?:en|dis)
# weak e-tag
W/"[^"]+"
# 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])
\\(?: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 (Unix, Java/Scala)
# Use if you have things like `-Pdocker` and want to treat them as `docker`
#(?:^|[\t ,>"'`=(])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (Windows / PowerShell)
# This is a subset of the more general compiler flags pattern.
# It avoids matching `-Path` to prevent it from being treated as `ath`
#(?:^|[\t ,"'`=(])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
# Compiler flags (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

View File

@@ -1,24 +1,21 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
(?:(?i)\.png$)
(?:^|/)(?i)COPYRIGHT
(?:^|/)(?i)LICEN[CS]E
(?:^|/)3rdparty/
(?:^|/)dirs$
(?:^|/)go\.mod$
(?:^|/)go\.sum$
(?:^|/)package(?:-lock|)\.json$
(?:^|/)Pipfile$
(?:^|/)pyproject.toml
(?:^|/)requirements(?:-dev|-doc|-test|)\.txt$
(?:^|/)sources(?:|\.dep)$
(?:^|/)vendor/
\.a$
\.ai$
\.all-contributorsrc$
\.avi$
\.bmp$
\.bz2$
\.cer$
\.class$
\.coveragerc$
\.crl$
\.crt$
\.csr$
@@ -30,15 +27,11 @@
\.eps$
\.exe$
\.gif$
\.git-blame-ignore-revs$
\.gitattributes$
\.gitignore$
\.gitkeep$
\.graffle$
\.gz$
\.icns$
\.ico$
\.ipynb$
\.jar$
\.jks$
\.jpeg$
@@ -48,62 +41,61 @@
\.lock$
\.map$
\.min\..
\.mo$
\.mod$
\.mp3$
\.mp4$
\.o$
\.ocf$
\.otf$
\.p12$
\.parquet$
\.pbxproj$
\.pdf$
\.pem$
\.pfx$
\.png$
\.psd$
\.pyc$
\.pylintrc$
\.qm$
\.runsettings$
\.s$
\.sig$
\.so$
\.svg$
\.svgz$
\.sys$
\.svgz?$
\.tar$
\.tgz$
\.tiff?$
\.ttf$
\.vcxproj\.filters$
\.vsdx$
\.wav$
\.webm$
\.webp$
\.woff
\.woff2?$
\.xcf$
\.xls
\.xlsx?$
\.xpm$
\.xz$
\.yml$
\.zip$
^\.github/actions/spelling/
^\.github/fabricbot.json$
^\.gitignore$
^\Q.git-blame-ignore-revs\E$
^\Q.github/workflows/spelling.yml\E$
^\Qbuild/config/release.gdnbaselines\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/host/ft_uia/run.bat\E$
^\Qsrc/host/runft.bat\E$
^\Qsrc/tools/lnkd/lnkd.bat\E$
^\Qsrc/tools/pixels/pixels.bat\E$
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
^\XamlStyler.json$
^build/config/
^consolegit2gitfilters\.json$
^dep/
^doc/reference/master-sequence-list\.csv$
^doc/reference/master-sequence-list.csv$
^doc/reference/UTF8-torture-test\.txt$
^doc/reference/windows-terminal-logo\.ans$
^oss/
^samples/PixelShaders/Screenshots/
^src/host/ft_uia/run\.bat$
^src/host/runft\.bat$
^src/host/runut\.bat$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/atlas/
^src/renderer/wddmcon/WddmConRenderer\.
@@ -115,13 +107,14 @@
^src/terminal/parser/ut_parser/Base64Test.cpp$
^src/terminal/parser/ut_parser/run\.bat$
^src/tools/benchcat
^src/tools/integrity/dirs$
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
^src/tools/RenderingTests/main\.cpp$
^src/tools/lnkd/lnkd\.bat$
^src/tools/pixels/pixels\.bat$
^src/tools/RenderingTests/main.cpp$
^src/tools/texttests/fira\.txt$
^src/tools/U8U16Test/(?!en)..\.
^src/types/ColorFix\.cpp$
^src/types/ut_types/UtilsTests\.cpp$
^tools/ReleaseEngineering/ServicingPipeline\.ps1$
^XamlStyler\.json$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^src/types/ColorFix.cpp
^src/types/ut_types/UtilsTests.cpp$
^tools/ReleaseEngineering/ServicingPipeline.ps1$
ignore$
SUMS$

View File

@@ -1,5 +0,0 @@
EOB
swrapped
wordi
wordiswrapped
wrappe

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
WCAG
winui
appshellintegration
mdtauk

View File

@@ -1,6 +1,4 @@
# reject `m_data` as VxWorks defined it and that breaks things if it's used elsewhere
# see [fprime](https://github.com/nasa/fprime/commit/d589f0a25c59ea9a800d851ea84c2f5df02fb529)
# and [Qt](https://github.com/qtproject/qt-solutions/blame/fb7bc42bfcc578ff3fa3b9ca21a41e96eb37c1c7/qtscriptclassic/src/qscriptbuffer_p.h#L46)
# 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,
@@ -8,72 +6,40 @@
# to use this:
#\bfit\(
# s.b. anymore
\bany more[,.]
# s.b. GitHub
(?<![&*.]|// |\btype )\bGithub\b(?![{)])
\bGithub\b
# s.b. GitLab
(?<![&*.]|// |\btype )\bGitlab\b(?![{)])
\bGitlab\b
# s.b. JavaScript
\bJavascript\b
# s.b. macOS or Mac OS X or ...
\bMacOS\b
# s.b. Microsoft
\bMicroSoft\b
# s.b. TypeScript
\bTypescript\b
# s.b. another
\ban[- ]other\b
# s.b. deprecation warning
\b[Dd]epreciation [Ww]arnings?\b
# s.b. greater than
\bgreater then\b
# s.b. in front of
\bin from of\b
# s.b. into
# when not phrasal and when `in order to` would be wrong:
# https://thewritepractice.com/into-vs-in-to/
#\sin to\s(?!if\b)
# s.b. is obsolete
\bis obsolescent\b
# s.b. it's or its
\bits[']
#\sin to\s
# s.b. opt-in
#(?<!\sfor)\sopt in\s
\sopt in\s
# s.b. less than
\bless then\b
# s.b. one of
\bon of\b
# s.b. otherwise
\bother[- ]wise\b
# s.b. or (more|less)
\bore (?:more|less)\b
# s.b. nonexistent
\bnon existing\b
\b[Nn]o[nt][- ]existent\b
# s.b. brief / details/ param / return / retval
(?:^\s*|(?:\*|//|/*)\s+`)[\\@](?:breif|(?:detail|detials)|(?:params(?!\.)|prama?)|ret(?:uns?)|retvl)\b
# s.b. preexisting
[Pp]re[- ]existing
@@ -83,37 +49,14 @@
# s.b. preemptively
[Pp]re[- ]emptively
# s.b. recently changed or recent changes
[Rr]ecent changed
# s.b. reentrancy
[Rr]e[- ]entrancy
# s.b. reentrant
[Rr]e[- ]entrant
# s.b. understand
\bunder stand\b
# s.b. workaround(s)
#\bwork[- ]arounds?\b
# s.b. workarounds
#\bwork[- ]arounds\b
# s.b. workaround
(?:(?:[Aa]|[Tt]he|ugly)\swork[- ]around\b|\swork[- ]around\s+for)
# s.b. (coarse|fine)-grained
\b(?:coarse|fine) grained\b
# s.b. neither/nor -- or reword
#\bnot\b[^.?!"/(]+\bnor\b
# probably a double negative
# s.b. neither/nor (plus rewording the beginning)
\bnot\b[^.?!"/]*\bneither\b[^.?!"/(]*\bnor\b
# In English, it is generally wrong to have the same word twice in a row without punctuation.
# Duplicated words are generally mistakes.
# There are a few exceptions where it is acceptable (e.g. "that that").
# If the highlighted doubled word pair is in a code snippet, you can write a pattern to mask it.
# If the highlighted doubled word pair is in prose, have someone read the English before you dismiss this error.
# Reject duplicate words
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s

View File

@@ -0,0 +1,2 @@
\\native(?![a-z])
\\nihilist(?![a-z])

View File

@@ -0,0 +1,8 @@
\\registry(?![a-z])
\\release(?![a-z])
\\resources?(?![a-z])
\\result(?![a-z])
\\resultmacros(?![a-z])
\\rules(?![a-z])
\\renderer(?![a-z])
\\rectread(?![a-z])

View File

@@ -0,0 +1,13 @@
\\telemetry(?![a-z])
\\templates(?![a-z])
\\term(?![a-z])
\\terminal(?![a-z])
\\terminalcore(?![a-z])
\\terminalinput(?![a-z])
\\testlist(?![a-z])
\\testmd(?![a-z])
\\testpasses(?![a-z])
\\tests(?![a-z])
\\thread(?![a-z])
\\tools(?![a-z])
\\types?(?![a-z])

View File

@@ -7,6 +7,10 @@ Note: order of the contents of these files can matter.
Lines from an individual file are handled in file order.
Files are selected in alphabetical order.
* [n](0_n.txt), [r](0_r.txt), and [t](0_t.txt) are specifically to work around
a quirk in the spell checker:
it often sees C strings of the form "Hello\nwerld". And would prefer to
spot the typo of `werld`.
* [patterns](patterns.txt) is the main list -- there is nothing
particularly special about the file name (beyond the extension which is
important).

View File

@@ -3,7 +3,7 @@
https?://\S+
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}(?!\[)[Uu]?[Ll]{0,2}\b
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]{0,2}\b
microsoft/cascadia-code\@[0-9a-fA-F]{40}
\d+x\d+Logo
Scro\&ll
@@ -12,6 +12,7 @@ Scro\&ll
TestUtils::VerifyExpectedString\(tb, L"[^"]+"
(?:hostSm|mach)\.ProcessString\(L"[^"]+"
\b([A-Za-z])\g{-1}{3,}\b
0x[0-9A-Za-z]+
Base64::s_(?:En|De)code\(L"[^"]+"
VERIFY_ARE_EQUAL\(L"[^"]+"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"
@@ -23,129 +24,70 @@ ROY\sG\.\sBIV
!(?:(?i)ESC)!\[
!(?:(?i)CSI)!(?:\d+(?:;\d+|)m|[ABCDF])
# Python stringprefix / binaryprefix
\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'
# SSE intrinsics like "_mm_subs_epu16"
\b_mm(?:|256|512)_\w+\b
# ARM NEON intrinsics like "vsubq_u16"
\bv\w+_[fsu](?:8|16|32|64)\b
# color floating numbers
0x[0-9a-f](?:\.[0-9a-f]*p)[-+]\d+f
# AppX package
_\d[0-9a-z]{12}['\.]
# string test
equals_insensitive_ascii\("\w+", "\w+"
# Automatically suggested patterns
# hit-count: 3788 file-count: 599
# IServiceProvider / isAThing
\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 3831 file-count: 582
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 314 file-count: 21
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 71 file-count: 35
# Compiler flags
(?:^|[\t ,"'`=(])-[D](?=[A-Z]{2,}|[A-Z][a-z])
(?:^|[\t ,"'`=(])-[X](?!aml)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# hit-count: 47 file-count: 11
# special cased printf markers
\\r\\n(?=[a-z])|(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*(?:<.*['"`]|"(?:[;,]|\);)$|\) \+$))
# ConsoleArgumentsTests
--headless\\.*?"
# hit-count: 109 file-count: 62
# Compiler flags (Unix, Java/Scala)
# Use if you have things like `-Pdocker` and want to treat them as `docker`
(?:^|[\t ,>"'`=(])-(?:D(?=[A-Z])|[WX]|f(?=[ms]))(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# hit-count: 60 file-count: 35
# 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: 2 file-count: 2
# This does not cover multiline strings, if your repository has them,
# you'll want to remove the `(?=.*?")` suffix.
# The `(?=.*?")` suffix should limit the false positives rate
# printf
%(?:s)(?!ize)(?=[a-z]{2,})
# hit-count: 20 file-count: 9
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 16 file-count: 10
# 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: 13 file-count: 4
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
# hit-count: 7 file-count: 5
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# hit-count: 7 file-count: 1
# regex choice
\(\?:[^)]+\|[^)]+\)
# hit-count: 4 file-count: 4
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# hit-count: 4 file-count: 1
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
# hit-count: 4 file-count: 1
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
## You could manually change `(?i)X...` to use `[Xx]...`
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
# Lorem
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# hit-count: 3 file-count: 3
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# hit-count: 4 file-count: 1
# ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# hit-count: 2 file-count: 1
# Python string prefix / binary prefix
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?=[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# hit-count: 1 file-count: 1
# Punycode
\bxn--[-0-9a-z]+
# 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
# latex (check-spelling >= 0.0.22)
\\\w{2,}\{
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# hit-count: 1 file-count: 1
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# Questionably acceptable forms of `in to`
# Personally, I prefer `log into`, but people object
# https://www.tprteaching.com/log-into-log-in-to-login/
\b(?:[Ll]og|[Ss]ign) in to\b
# to opt in
\bto opt in\b
# 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][-Ssx]){3}\s+\d+\s+\S+\s+\S+\s+\d+\s+
# mount
\bmount\s+-t\s+(\w+)\s+\g{-1}\b
# C types and repeated CSS values
\s(auto|center|div|Guid|inherit|long|LONG|none|normal|solid|that|thin|transparent|very)(?: \g{-1})+\s
# C struct
\bstruct\s+(\w+)\s+\g{-1}\b
# go templates
\s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml):
# doxygen / javadoc / .net
(?:[\\@](?:brief|groupname|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+static|\s+override|\s+readonly)*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s
[-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*$

View File

@@ -1,7 +1,6 @@
^attache$
^attacher$
^attachers$
^bellow$
benefitting
occurences?
^dependan.*

View File

@@ -7,13 +7,13 @@ on:
- labeled
- unlabeled
permissions: {}
permissions: {}
jobs:
add-to-project:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v0.5.0
- uses: actions/add-to-project@v0.3.0
with:
project-url: https://github.com/orgs/microsoft/projects/159
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}

View File

@@ -1,32 +0,0 @@
name: GitGudSimilarIssues comments
on:
issues:
types: [opened]
jobs:
getSimilarIssues:
runs-on: ubuntu-latest
outputs:
message: ${{ steps.getBody.outputs.message }}
steps:
- id: getBody
uses: craigloewen-msft/GitGudSimilarIssues@main
with:
issuetitle: ${{ github.event.issue.title }}
repo: ${{ github.repository }}
similaritytolerance: "0.75"
add-comment:
needs: getSimilarIssues
runs-on: ubuntu-latest
permissions:
issues: write
if: needs.getSimilarIssues.outputs.message != ''
steps:
- name: Add comment
run: gh issue comment "$NUMBER" --repo "$REPO" --body "$BODY"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NUMBER: ${{ github.event.issue.number }}
REPO: ${{ github.repository }}
BODY: ${{ needs.getSimilarIssues.outputs.message }}

View File

@@ -5,7 +5,7 @@ name: Spell checking
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
#
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
# (in odd cases, it might actually run just to collapse a comment, but that's fairly rare)
# (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
@@ -34,29 +34,6 @@ name: Spell checking
#
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
# Sarif reporting
#
# Access to Sarif reports is generally restricted (by GitHub) to members of the repository.
#
# Requires enabling `security-events: write`
# and configuring the action with `use_sarif: 1`
#
# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Sarif-output
# Minimal workflow structure:
#
# on:
# push:
# ...
# pull_request_target:
# ...
# jobs:
# # you only want the spelling job, all others should be omitted
# spelling:
# # remove `security-events: write` and `use_sarif: 1`
# # remove `experimental_apply_changes_via_bot: 1`
# ... otherwise adjust the `with:` as you wish
on:
push:
branches:
@@ -66,6 +43,8 @@ on:
pull_request_target:
branches:
- "**"
tags-ignore:
- "**"
types:
- 'opened'
- 'reopened'
@@ -81,11 +60,10 @@ jobs:
contents: read
pull-requests: read
actions: read
security-events: write
outputs:
followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest
if: ${{ contains(github.event_name, 'pull_request') || github.event_name == 'push' }}
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'"
concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress
@@ -93,50 +71,35 @@ jobs:
steps:
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@v0.0.22
uses: check-spelling/check-spelling@v0.0.21
with:
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
suppress_push_for_open_pull_request: 1
checkout: true
check_file_names: 1
spell_check_this: microsoft/terminal@main
spell_check_this: check-spelling/spell-check-this@prerelease
post_comment: 0
use_magic_file: 1
report-timing: 1
warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }}
extra_dictionary_limit: 20
extra_dictionary_limit: 10
extra_dictionaries:
cspell:software-terms/dict/softwareTerms.txt
cspell:cpp/src/stdlib-cpp.txt
cspell:lorem-ipsum/dictionary.txt
cspell:cpp/src/stdlib-c.txt
cspell:php/dict/php.txt
cspell:filetypes/filetypes.txt
cspell:java/src/java.txt
cspell:python/src/common/extra.txt
cspell:node/dict/node.txt
cspell:java/src/java-terms.txt
cspell:aws/aws.txt
cspell:typescript/dict/typescript.txt
cspell:dotnet/dict/dotnet.txt
cspell:golang/dict/go.txt
cspell:fullstack/dict/fullstack.txt
cspell:cpp/src/compiler-msvc.txt
cspell:software-terms/src/software-terms.txt
cspell:python/src/python/python-lib.txt
cspell:mnemonics/src/mnemonics.txt
cspell:cpp/src/stdlib-cmath.txt
cspell:css/dict/css.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:django/dict/django.txt
cspell:npm/npm.txt
cspell:dotnet/dotnet.txt
cspell:python/src/python/python.txt
cspell:html/dict/html.txt
cspell:cpp/src/ecosystem.txt
cspell:cpp/src/compiler-clang-attributes.txt
cspell:npm/dict/npm.txt
cspell:r/src/r.txt
cspell:powershell/dict/powershell.txt
cspell:csharp/csharp.txt
cspell:css/css.txt
cspell:cpp/src/stdlib-cmath.txt
check_extra_dictionaries: ''
comment-push:
name: Report (Push)
@@ -148,10 +111,10 @@ jobs:
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.22
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: microsoft/terminal@main
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}
comment-pr:
@@ -160,38 +123,12 @@ jobs:
runs-on: ubuntu-latest
needs: spelling
permissions:
contents: read
pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.22
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: microsoft/terminal@main
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
update:
name: Update PR
permissions:
contents: write
pull-requests: write
actions: read
runs-on: ubuntu-latest
if: ${{
github.repository_owner != 'microsoft' &&
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '@check-spelling-bot apply')
}}
concurrency:
group: spelling-update-${{ github.event.issue.number }}
cancel-in-progress: false
steps:
- name: apply spelling updates
uses: check-spelling/check-spelling@v0.0.22
with:
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
checkout: true
ssh_key: "${{ secrets.CHECK_SPELLING }}"

View File

@@ -14,7 +14,7 @@ The point of doing all this work in public is to ensure that we are holding ours
The team triages new issues several times a week. During triage, the team uses labels to categorize, manage, and drive the project workflow.
We employ [a bot engine](./doc/bot.md) to help us automate common processes within our workflow.
We employ [a bot engine](https://github.com/microsoft/terminal/blob/main/doc/bot.md) to help us automate common processes within our workflow.
We drive the bot by tagging issues with specific labels which cause the bot engine to close issues, merge branches, etc. This bot engine helps us keep the repo clean by automating the process of notifying appropriate parties if/when information/follow-up is needed, and closing stale issues/PRs after reminders have remained unanswered for several days.

View File

@@ -1,4 +1,4 @@
![terminal-logos](https://github.com/microsoft/terminal/assets/91625426/333ddc76-8ab2-4eb4-a8c0-4d7b953b1179)
![terminal-logos](https://user-images.githubusercontent.com/48369326/115790869-4c852b00-a37c-11eb-97f1-f61972c7800c.png)
# Welcome to the Windows Terminal, Console and Command-Line repo
@@ -8,8 +8,8 @@ This repository contains the source code for:
* [Windows Terminal Preview](https://aka.ms/terminal-preview)
* The Windows console host (`conhost.exe`)
* Components shared between the two projects
* [ColorTool](./src/tools/ColorTool)
* [Sample projects](./samples)
* [ColorTool](https://github.com/microsoft/terminal/tree/main/src/tools/ColorTool)
* [Sample projects](https://github.com/microsoft/terminal/tree/main/samples)
that show how to consume the Windows Console APIs
Related repositories include:
@@ -21,7 +21,7 @@ Related repositories include:
## Installing and running Windows Terminal
> [!NOTE]
> **Note**\
> Windows Terminal requires Windows 10 2004 (build 19041) or later
### Microsoft Store [Recommended]
@@ -53,7 +53,7 @@ fails for any reason, you can try the following command at a PowerShell prompt:
Add-AppxPackage Microsoft.WindowsTerminal_<versionNumber>.msixbundle
```
> [!NOTE]
> **Note**\
> If you install Terminal manually:
>
> * You may need to install the [VC++ v14 Desktop Framework Package](https://docs.microsoft.com/troubleshoot/cpp/c-runtime-packages-desktop-bridge#how-to-install-and-update-desktop-framework-packages).
@@ -72,8 +72,8 @@ package:
winget install --id Microsoft.WindowsTerminal -e
```
> [!NOTE]
> Dependency support is available in WinGet version [1.6.2631 or later](https://github.com/microsoft/winget-cli/releases). To install the Terminal stable release 1.18 or later, please make sure you have the updated version of the WinGet client.
> **Note**\
> Due to [a dependency issue](https://github.com/microsoft/terminal/issues/15663), Terminal's current versions cannot be installed via the Windows Package Manager CLI. To install the stable release 1.17 or later, or the Preview release 1.18 or later, please use an alternative installation method.
#### Via Chocolatey (unofficial)
@@ -118,28 +118,6 @@ repository.
---
## Installing Windows Terminal Canary
Windows Terminal Canary is a nightly build of Windows Terminal. This build has the latest code from our `main` branch, giving you an opportunity to try features before they make it to Windows Terminal Preview.
Windows Terminal Canary is our least stable offering, so you may discover bugs before we have had a chance to find them.
Windows Terminal Canary is available as an App Installer distribution and a Portable ZIP distribution.
The App Installer distribution supports automatic updates. Due to platform limitations, this installer only works on Windows 11.
The Portable ZIP distribution is a portable application. It will not automatically update and will not automatically check for updates. This portable ZIP distribution works on Windows 10 (19041+) and Windows 11.
| Distribution | Architecture | Link |
|---------------|:---------------:|------------------------------------------------------|
| App Installer | x64, arm64, x86 | [download](https://aka.ms/terminal-canary-installer) |
| Portable ZIP | x64 | [download](https://aka.ms/terminal-canary-zip-x64) |
| Portable ZIP | ARM64 | [download](https://aka.ms/terminal-canary-zip-arm64) |
| Portable ZIP | x86 | [download](https://aka.ms/terminal-canary-zip-x86) |
_Learn more about the [types of Windows Terminal distributions](https://learn.microsoft.com/windows/terminal/distributions)._
---
## Windows Terminal Roadmap
The plan for the Windows Terminal [is described here](/doc/roadmap-2023.md) and
@@ -262,7 +240,7 @@ Cause: You're launching the incorrect solution in Visual Studio.
Solution: Make sure you're building & deploying the `CascadiaPackage` project in
Visual Studio.
> [!NOTE]
> **Note**\
> `OpenConsole.exe` is just a locally-built `conhost.exe`, the classic
> Windows Console that hosts Windows' command-line infrastructure. OpenConsole
> is used by Windows Terminal to connect to and communicate with command-line
@@ -286,7 +264,7 @@ enhance Windows Terminal\!
***BEFORE you start work on a feature/fix***, please read & follow our
[Contributor's
Guide](./CONTRIBUTING.md) to
Guide](https://github.com/microsoft/terminal/blob/main/CONTRIBUTING.md) to
help avoid any wasted or duplicate effort.
## Communicating with the Team
@@ -387,10 +365,10 @@ Please review these brief docs below about our coding practices.
This is a work in progress as we learn what we'll need to provide people in
order to be effective contributors to our project.
* [Coding Style](./doc/STYLE.md)
* [Code Organization](./doc/ORGANIZATION.md)
* [Exceptions in our legacy codebase](./doc/EXCEPTIONS.md)
* [Helpful smart pointers and macros for interfacing with Windows in WIL](./doc/WIL.md)
* [Coding Style](https://github.com/microsoft/terminal/blob/main/doc/STYLE.md)
* [Code Organization](https://github.com/microsoft/terminal/blob/main/doc/ORGANIZATION.md)
* [Exceptions in our legacy codebase](https://github.com/microsoft/terminal/blob/main/doc/EXCEPTIONS.md)
* [Helpful smart pointers and macros for interfacing with Windows in WIL](https://github.com/microsoft/terminal/blob/main/doc/WIL.md)
---

View File

@@ -14,4 +14,4 @@ Support for Windows Terminal is limited to the resources listed above.
[gh-bug]: https://github.com/microsoft/terminal/issues/new?assignees=&labels=Issue-Bug&template=bug_report.md&title=
[gh-feature]: https://github.com/microsoft/terminal/issues/new?assignees=&labels=Issue-Feature&template=Feature_Request.md&title=
[docs]: https://docs.microsoft.com/windows/terminal
[contributor]: ./CONTRIBUTING.md
[contributor]: https://github.com/microsoft/terminal/blob/main/CONTRIBUTING.md

View File

@@ -9,7 +9,7 @@
<PropertyGroup>
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
<PGOBranch>main</PGOBranch>
<PGOBranch>release-1.19</PGOBranch>
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>

View File

@@ -102,7 +102,7 @@ stages:
- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
- stage: CodeIndexer
displayName: GitHub CodeNav Indexer
displayName: Github CodeNav Indexer
dependsOn: []
jobs:
- template: ./templates-v2/job-index-github-codenav.yml

View File

@@ -0,0 +1,43 @@
trigger: none
pr: none
schedules:
- cron: "30 3 * * 2-6" # Run at 03:30 UTC Tuesday through Saturday (After the work day in Pacific, Mon-Fri)
displayName: "Nightly Terminal Build"
branches:
include:
- main
always: false # only run if there's code changes!
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
parameters:
- name: publishToAzure
displayName: "Deploy to **PUBLIC** Azure Storage"
type: boolean
default: true
extends:
template: templates-v2\pipeline-full-release-build.yml
parameters:
branding: Canary
buildTerminal: true
pgoBuildMode: Optimize
codeSign: true
generateSbom: true
publishSymbolsToPublic: true
publishVpackToWindows: false
symbolExpiryTime: 15 # Nightly builds do not keep symbols for very long!
${{ if eq(true, parameters.publishToAzure) }}:
extraPublishJobs:
- template: job-deploy-to-azure-storage.yml
parameters:
pool:
name: SHINE-INT-S
dependsOn: [PublishSymbols]
storagePublicRootURL: $(AppInstallerRootURL)
subscription: $(AzureSubscriptionName)
storageAccount: $(AzureStorageAccount)
storageContainer: $(AzureStorageContainer)
buildConfiguration: Release
environment: production-canary

View File

@@ -35,13 +35,9 @@ extends:
symbolExpiryTime: 15
${{ if eq(true, parameters.publishToAzure) }}:
extraPublishJobs:
- template: build/pipelines/templates-v2/job-deploy-to-azure-storage.yml@self
- template: job-deploy-to-azure-storage.yml
parameters:
pool: { type: windows }
variables:
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: "$(Build.SourcesDirectory)/_none"
dependsOn: [PublishSymbols]
storagePublicRootURL: $(AppInstallerRootURL)
subscription: $(AzureSubscriptionName)

View File

@@ -0,0 +1,85 @@
trigger: none
pr: none
# Expose all of these parameters for user configuration.
parameters:
- name: branding
displayName: "Branding (Build Type)"
type: string
default: Release
values:
- Release
- Preview
- Canary
- Dev
- name: buildTerminal
displayName: "Build Windows Terminal MSIX"
type: boolean
default: true
- name: buildConPTY
displayName: "Build ConPTY NuGet"
type: boolean
default: false
- name: buildWPF
displayName: "Build Terminal WPF Control"
type: boolean
default: false
- name: pgoBuildMode
displayName: "PGO Build Mode"
type: string
default: Optimize
values:
- Optimize
- Instrument
- None
- name: buildConfigurations
displayName: "Build Configurations"
type: object
default:
- Release
- name: buildPlatforms
displayName: "Build Platforms"
type: object
default:
- x64
- x86
- arm64
- name: codeSign
displayName: "Sign all build outputs"
type: boolean
default: true
- name: generateSbom
displayName: "Generate a Bill of Materials"
type: boolean
default: true
- name: terminalInternalPackageVersion
displayName: "Terminal Internal Package Version"
type: string
default: '0.0.8'
- name: publishSymbolsToPublic
displayName: "Publish Symbols to MSDL"
type: boolean
default: true
- name: publishVpackToWindows
displayName: "Publish VPack to Windows"
type: boolean
default: false
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
extends:
template: templates-v2/pipeline-full-release-build.yml
parameters:
branding: ${{ parameters.branding }}
buildTerminal: ${{ parameters.buildTerminal }}
buildConPTY: ${{ parameters.buildConPTY }}
buildWPF: ${{ parameters.buildWPF }}
pgoBuildMode: ${{ parameters.pgoBuildMode }}
buildConfigurations: ${{ parameters.buildConfigurations }}
buildPlatforms: ${{ parameters.buildPlatforms }}
codeSign: ${{ parameters.codeSign }}
generateSbom: ${{ parameters.generateSbom }}
terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }}
publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }}
publishVpackToWindows: ${{ parameters.publishVpackToWindows }}

View File

@@ -92,11 +92,6 @@ jobs:
# Yup.
BuildTargetParameter: ' '
SelectedSigningFragments: ' '
# When building the unpackaged distribution, build it in portable mode if it's Canary-branded
${{ if eq(parameters.branding, 'Canary') }}:
UnpackagedBuildArguments: -PortableMode
${{ else }}:
UnpackagedBuildArguments: ' '
JobOutputDirectory: $(Terminal.BinDir)
JobOutputArtifactName: build-$(BuildPlatform)-$(BuildConfiguration)${{ parameters.artifactStem }}
${{ insert }}: ${{ parameters.variables }}
@@ -274,7 +269,7 @@ jobs:
- pwsh: |-
$XamlAppxPath = (Get-Item "src\cascadia\CascadiaPackage\AppPackages\*\Dependencies\$(BuildPlatform)\Microsoft.UI.Xaml*.appx").FullName
$outDir = New-Item -Type Directory "$(Terminal.BinDir)/_unpackaged" -ErrorAction:Ignore
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 $(UnpackagedBuildArguments) -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination $outDir.FullName
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination $outDir.FullName
displayName: Build Unpackaged Distribution (from MSIX)
condition: and(succeeded(), ne(variables.WindowsTerminalPackagePath, ''))

View File

@@ -1,8 +1,6 @@
parameters:
- name: buildConfiguration
type: string
- name: buildPlatforms
type: object
- name: pool
type: object
default: []
@@ -27,66 +25,46 @@ parameters:
type: string
jobs:
- job: DeployAzure
- deployment: DeployAzure
${{ if ne(length(parameters.pool), 0) }}:
pool: ${{ parameters.pool }}
displayName: Publish to Azure Storage (Prod)
dependsOn: ${{ parameters.dependsOn }}
variables:
${{ insert }}: ${{ parameters.variables }}
steps:
- download: none
environment: ${{ parameters.environment }}
strategy:
runOnce:
deploy:
steps:
- download: none
- checkout: self
clean: true
fetchDepth: 1
fetchTags: false # Tags still result in depth > 1 fetch; we don't need them here
submodules: true
persistCredentials: True
- checkout: self
clean: true
fetchDepth: 1
fetchTags: false # Tags still result in depth > 1 fetch; we don't need them here
submodules: true
persistCredentials: True
- task: DownloadPipelineArtifact@2
displayName: Download MSIX Bundle Artifact
inputs:
artifactName: appxbundle-${{ parameters.buildConfiguration }}${{ parameters.artifactStem }}
downloadPath: '$(Build.SourcesDirectory)/_out'
itemPattern: '**/*.msixbundle'
- task: DownloadPipelineArtifact@2
displayName: Download MSIX Bundle Artifact
inputs:
artifactName: appxbundle-${{ parameters.buildConfiguration }}${{ parameters.artifactStem }}
downloadPath: '$(Build.SourcesDirectory)/_out'
itemPattern: '**/*.msixbundle'
- ${{ each platform in parameters.buildPlatforms }}:
- task: DownloadPipelineArtifact@2
displayName: Download unpackaged build for ${{ platform }} ${{ parameters.buildConfiguration }}
inputs:
artifactName: build-${{ platform }}-${{ parameters.buildConfiguration }}${{ parameters.artifactStem }}
downloadPath: '$(Build.SourcesDirectory)/_unpackaged'
itemPattern: '**/_unpackaged/*.zip'
- pwsh: |-
$b = Get-Item _out/*.msixbundle
./build/scripts/New-AppInstallerFromTemplateAndBundle.ps1 -BundlePath $b.FullName -AppInstallerTemplatePath ./build/config/template.appinstaller -AppInstallerRoot "${{ parameters.storagePublicRootURL }}" -OutputPath _out/Microsoft.WindowsTerminalCanary.appinstaller
displayName: "Produce AppInstaller for MSIX bundle"
- pwsh: |-
$b = Get-Item _out/*.msixbundle
./build/scripts/New-AppInstallerFromTemplateAndBundle.ps1 -BundlePath $b.FullName -AppInstallerTemplatePath ./build/config/template.appinstaller -AppInstallerRoot "${{ parameters.storagePublicRootURL }}" -OutputPath _out/Microsoft.WindowsTerminalCanary.appinstaller
displayName: "Produce AppInstaller for MSIX bundle"
- pwsh: |-
$zips = Get-ChildItem -Recurse -Filter *.zip _unpackaged
$zips | ForEach-Object {
$name = $_.Name
$parts = $name.Split('_')
$parts[1] = "latest"
$name = [String]::Join('_', $parts)
$_ | Move-Item -Destination (Join-Path "_out" $name)
}
displayName: "Wrangle Unpackaged builds into place, rename"
- powershell: |-
Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute
displayName: Install Azure Module Dependencies
- task: AzureFileCopy@5
displayName: Publish to Storage Account
inputs:
sourcePath: _out/*
Destination: AzureBlob
azureSubscription: ${{ parameters.subscription }}
storage: ${{ parameters.storageAccount }}
ContainerName: ${{ parameters.storageContainer }}
AdditionalArgumentsForBlobCopy: "--content-type application/octet-stream"
- task: AzureFileCopy@5
displayName: Publish to Storage Account
inputs:
sourcePath: _out/*
Destination: AzureBlob
azureSubscription: ${{ parameters.subscription }}
storage: ${{ parameters.storageAccount }}
ContainerName: ${{ parameters.storageContainer }}
AdditionalArgumentsForBlobCopy: "--content-type application/octet-stream"

View File

@@ -1,6 +1,6 @@
jobs:
- job: CodeNavIndexer
displayName: Run GitHub CodeNav Indexer
displayName: Run Github CodeNav Indexer
pool: { vmImage: windows-2022 }
steps:

View File

@@ -46,9 +46,6 @@ parameters:
- name: publishSymbolsToPublic
type: boolean
default: true
- name: symbolExpiryTime
type: string
default: 36530 # This is the default from PublishSymbols@2
- name: publishVpackToWindows
type: boolean
default: false
@@ -205,15 +202,10 @@ extends:
generateSbom: false # Handled by onebranch
codeSign: ${{ parameters.codeSign }}
afterBuildSteps:
# This directory has to exist, even if we aren't using createvpack, because the Guardian rules demand it.
- pwsh: |-
New-Item "$(JobOutputDirectory)/vpack" -Type Directory
displayName: Make sure the vpack directory exists
- ${{ if parameters.publishVpackToWindows }}:
- pwsh: |-
Copy-Item -Verbose -Path "$(MsixBundlePath)" -Destination (Join-Path "$(JobOutputDirectory)/vpack" 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle')
displayName: Stage msixbundle for vpack
$d = New-Item "$(JobOutputDirectory)/vpack" -Type Directory
Copy-Item -Verbose -Path "$(MsixBundlePath)" -Destination (Join-Path $d 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle')
displayName: Stage msixbundle for vpack
- ${{ if eq(parameters.buildConPTY, true) }}:
- template: ./build/pipelines/templates-v2/job-package-conpty.yml@self
@@ -247,14 +239,13 @@ extends:
- stage: Publish
displayName: Publish
dependsOn: [Build, Package]
dependsOn: [Build]
jobs:
- template: ./build/pipelines/templates-v2/job-publish-symbols.yml@self
parameters:
pool: { type: windows }
includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }}
symbolPatGoesInTaskInputs: true # onebranch tries to muck with the PAT variable, so we need to change how it get the PAT
symbolExpiryTime: ${{ parameters.symbolExpiryTime }}
variables:
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true

View File

@@ -25,12 +25,7 @@ Param(
[Parameter(HelpMessage="Path to makeappx.exe", ParameterSetName='Layout')]
[ValidateScript({Test-Path $_ -Type Leaf})]
[string]
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakeAppx.exe",
[Parameter(HelpMessage="Include the portable mode marker file by default", ParameterSetName='AppX')]
[Parameter(HelpMessage="Include the portable mode marker file by default", ParameterSetName='Layout')]
[switch]
$PortableMode = $PSCmdlet.ParameterSetName -eq 'Layout'
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakeAppx.exe"
)
$filesToRemove = @("*.xml", "*.winmd", "Appx*", "Images/*Tile*", "Images/*Logo*") # Remove from Terminal
@@ -133,11 +128,6 @@ $finalTerminalPriFile = Join-Path $terminalAppPath "resources.pri"
# Packaging
########
$portableModeMarkerFile = Join-Path $terminalAppPath ".portable"
If ($PortableMode) {
"" | Out-File $portableModeMarkerFile
}
If ($PSCmdlet.ParameterSetName -Eq "AppX") {
# We only produce a ZIP when we're combining two AppX directories.
New-Item -ItemType Directory -Path $Destination -ErrorAction:SilentlyContinue | Out-Null

View File

@@ -5,7 +5,7 @@
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2023</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>
<VersionMinor>20</VersionMinor>
<VersionMinor>19</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
</PropertyGroup>
</Project>

View File

@@ -9,7 +9,7 @@
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230824.2" targetFramework="native" developmentDependency="true" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220201.1" targetFramework="native" developmentDependency="true" />
<!-- Managed packages -->
<package id="Appium.WebDriver" version="3.0.0.2" targetFramework="net45" />

View File

@@ -5,10 +5,10 @@
`.../console/published/wincon.w` in the OS repo when you submit the PR.
The branch won't build without it.
* For now, you can update winconp.h with your consumable changes.
* Define registry name (ex: `CONSOLE_REGISTRY_CURSORCOLOR`)
* Add the setting to `CONSOLE_STATE_INFO`.
* Define registry name (ex `CONSOLE_REGISTRY_CURSORCOLOR`)
* Add the setting to `CONSOLE_STATE_INFO`
* Define the property key ID and the property key itself.
- Yes, the large majority of the `DEFINE_PROPERTYKEY` defs are the same, it's only the last byte of the guid that changes.
- Yes, the large majority of the `DEFINE_PROPERTYKEY` defs are the same, it's only the last byte of the guid that changes
2. Add matching fields to Settings.hpp
- Add getters, setters, the whole drill.
@@ -17,9 +17,9 @@
- We need to add it to *reading and writing* the registry from the propsheet, and *reading* the link from the propsheet. Yes, that's weird, but the propsheet is smart enough to re-use ShortcutSerialization::s_SetLinkValues, but not smart enough to do the same with RegistrySerialization.
- `src/propsheet/registry.cpp`
- `propsheet/registry.cpp@InitRegistryValues` should initialize the default value for the property.
- `propsheet/registry.cpp@GetRegistryValues` should make sure to read the property from the registry.
- `propsheet/registry.cpp@GetRegistryValues` should make sure to read the property from the registry
4. Add the field to the propslib registry map.
4. Add the field to the propslib registry map
5. Add the value to `ShortcutSerialization.cpp`
- Read the value in `ShortcutSerialization::s_PopulateV2Properties`
@@ -30,11 +30,11 @@ Now, your new setting should be stored just like all the other properties.
7. Update the feature test properties to get add the setting as well
- `ft_uia/Common/NativeMethods.cs@WinConP`:
- `Wtypes.PROPERTYKEY PKEY_Console_`.
- `NT_CONSOLE_PROPS`.
- `Wtypes.PROPERTYKEY PKEY_Console_`
- `NT_CONSOLE_PROPS`
8. Add the default value for the setting to `win32k-settings.man`
- If the setting shouldn't default to 0 or `nullptr`, then you'll need to set the default value of the setting in `win32k-settings.man`.
9. Update `Settings::InitFromStateInfo` and `Settings::CreateConsoleStateInfo` to get/set the value in a CONSOLE_STATE_INFO appropriately.
9. Update `Settings::InitFromStateInfo` and `Settings::CreateConsoleStateInfo` to get/set the value in a CONSOLE_STATE_INFO appropriately

View File

@@ -51,7 +51,7 @@ Will this UI enhancement come to other apps on Windows? Almost certainly not. Th
Will we try to keep it from regressing? Yes! Right now it's sort of a manual process. We identify that something is getting slow and then we go haul out [WPR](https://docs.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-recorder) and start taking traces. We stare down the hot paths and try to reason out what is going on and then improve them. For instance, in the last cycle or two, we focused on heap allocations as a major area where we could improve our end-to-end performance, changing a ton of our code to use stack-constructed iterator-like facades over the underlying request buffer instead of translating and allocating it into a new heap space for each level of processing.
As an aside, @bitcrazed wants us to automate performance tests in some conhost specific way, but I haven't quite figured out a controlled environment to do this in yet. The Windows Engineering System runs performance tests each night that give us a coarse-grained way of knowing if we messed something up for the whole operating system, and they technically offer a fine-grained way for us to insert our own performance tests... but I just haven't got around to that yet. If you have an idea for a way for us to do this in an automated fashion, I'm all ears.
As an aside, @bitcrazed wants us to automate performance tests in some conhost specific way, but I haven't quite figured out a controlled environment to do this in yet. The Windows Engineering System runs performance tests each night that give us a coarse grained way of knowing if we messed something up for the whole operating system, and they technically offer a fine grained way for us to insert our own performance tests... but I just haven't got around to that yet. If you have an idea for a way for us to do this in an automated fashion, I'm all ears.
If there's anything else you'd like to know, let me know. I could go on all day. I deleted like 15 tangents from this reply before posting it....

View File

@@ -125,6 +125,8 @@
* Private calls into the Windows Window Manager to perform privileged actions related to the console process (working to eliminate) or for High DPI stuff (also working to eliminate)
* `Userprivapi.cpp`
* `Windowdpiapi.cpp`
* New UTF8 state machine in progress to improve Bash (and other apps) support for UTF-8 in console
* `Utf8ToWideCharParser.cpp`
* Window resizing/layout/management/window messaging loops and all that other stuff that has us interact with Windows to create a visual display surface and control the user interaction entry point
* `Window.cpp`
* `Windowproc.cpp`

View File

@@ -86,19 +86,12 @@
]
},
"BuiltinSuggestionSource": {
"type": "string",
"anyOf": [
{
"type": "string"
},
{
"enum": [
"commandHistory",
"tasks",
"all"
]
}
]
"enum": [
"commandHistory",
"tasks",
"all"
],
"type": "string"
},
"SuggestionSource": {
"default": "all",
@@ -106,17 +99,15 @@
"$comment": "`tasks` and `local` are sources that would be added by the Tasks feature, as a follow-up",
"oneOf": [
{
"type": "null"
},
{
"$ref": "#/$defs/BuiltinSuggestionSource"
"type": [ "string", "null", "BuiltinSuggestionSource" ]
},
{
"type": "array",
"items": {
"$ref": "#/$defs/BuiltinSuggestionSource"
},
"uniqueItems": true
"items": { "type": "BuiltinSuggestionSource" }
},
{
"type": "array",
"items": { "type": "string" }
}
]
},
@@ -210,6 +201,10 @@
"desktopWallpaper"
]
}
],
"type": [
"string",
"null"
]
},
"backgroundImageOpacity": {
@@ -275,7 +270,7 @@
"description": "Use to set a path to a pixel shader to use with the Terminal when unfocused. Overrides `experimental.retroTerminalEffect`. This is an experimental feature, and its continued existence is not guaranteed.",
"type": "string"
},
"useAcrylic": {
"useAcrylic":{
"description": "When set to true, the window will have an acrylic material background when unfocused. When set to false, the window will have a plain, untextured background when unfocused.",
"type": "boolean"
},
@@ -657,7 +652,6 @@
"$ref": "#/$defs/NewTabMenuEntry"
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
@@ -700,7 +694,6 @@
"$ref": "#/$defs/NewTabMenuEntry"
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
@@ -717,7 +710,6 @@
"$ref": "#/$defs/NewTabMenuEntry"
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
@@ -739,7 +731,6 @@
"$ref": "#/$defs/NewTabMenuEntry"
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
@@ -756,7 +747,6 @@
"$ref": "#/$defs/NewTabMenuEntry"
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
@@ -797,7 +787,6 @@
]
},
"ShortcutAction": {
"type": "object",
"properties": {
"action": {
"description": "The action to execute",
@@ -806,7 +795,8 @@
},
"required": [
"action"
]
],
"type": "object"
},
"AdjustFontSizeAction": {
"description": "Arguments corresponding to an Adjust Font Size Action",
@@ -815,7 +805,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -840,7 +829,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -882,7 +870,6 @@
"$ref": "#/$defs/NewTerminalArgs"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -899,7 +886,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -924,7 +910,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -949,7 +934,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -974,7 +958,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -999,7 +982,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1024,7 +1006,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1049,7 +1030,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1077,7 +1057,6 @@
"$ref": "#/$defs/NewTerminalArgs"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1110,7 +1089,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1148,7 +1126,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1176,7 +1153,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1198,7 +1174,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1220,7 +1195,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1245,7 +1219,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1266,7 +1239,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1287,7 +1259,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1308,7 +1279,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1333,7 +1303,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1362,7 +1331,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1391,7 +1359,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1420,7 +1387,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1445,7 +1411,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1470,7 +1435,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1494,7 +1458,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1520,7 +1483,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1542,7 +1504,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1570,7 +1531,6 @@
"$ref": "#/$defs/NewTerminalArgs"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1587,7 +1547,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1609,7 +1568,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1631,7 +1589,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1653,7 +1610,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1675,7 +1631,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1698,7 +1653,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1720,7 +1674,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1742,7 +1695,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1794,7 +1746,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1811,7 +1762,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1835,7 +1785,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1864,7 +1813,6 @@
"$ref": "#/$defs/ShortcutAction"
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
@@ -1951,11 +1899,7 @@
"properties": {
"applicationTheme": {
"description": "Which UI theme the Terminal should use for controls",
"enum": [
"light",
"dark",
"system"
],
"enum": [ "light", "dark", "system" ],
"type": "string"
},
"useMica": {
@@ -1986,11 +1930,7 @@
"type": "string",
"description": "The name of the theme. This will be displayed in the settings UI.",
"not": {
"enum": [
"light",
"dark",
"system"
]
"enum": [ "light", "dark", "system" ]
}
},
"tab": {
@@ -2007,7 +1947,6 @@
"ThemePair": {
"additionalProperties": false,
"description": "A pair of Theme names, to allow the Terminal to switch theme based on the OS theme",
"type": "object",
"properties": {
"light": {
"type": "string",
@@ -2189,16 +2128,16 @@
},
"name": {
"description": "The name that will appear in the command palette. If one isn't provided, the terminal will attempt to automatically generate a name.\nIf name is a string, it will be the name of the command.\nIf name is a object, the key property of the object will be used to lookup a localized string resource for the command",
"type": [
"string",
"object",
"null"
],
"properties": {
"key": {
"type": "string"
}
}
},
"type": [
"string",
"object",
"null"
]
},
"iterateOn": {
"type": "string",
@@ -2235,7 +2174,6 @@
"Globals": {
"additionalProperties": true,
"description": "Properties that affect the entire window, regardless of the profile settings.",
"type": "object",
"properties": {
"alwaysOnTop": {
"default": false,
@@ -2247,7 +2185,7 @@
"description": "When set to true, tabs are always displayed. When set to false and \"showTabsInTitlebar\" is set to false, tabs only appear after opening a new tab.",
"type": "boolean"
},
"compatibility.enableUnfocusedAcrylic": {
"compatibility.enableUnfocusedAcrylic":{
"default": true,
"description": "When set to true, unfocused windows can have acrylic instead of opaque.",
"type": "boolean"
@@ -2450,17 +2388,10 @@
"theme": {
"default": "dark",
"description": "Sets the theme of the application. This value should be the name of one of the themes defined in `themes`. The Terminal also includes the themes `dark`, `light`, and `system`.",
"anyOf": [
"oneOf": [
{
"type": "string"
},
{
"enum": [
"dark",
"light",
"system"
]
},
{
"$ref": "#/$defs/ThemePair"
}
@@ -2570,12 +2501,12 @@
},
"required": [
"defaultProfile"
]
],
"type": "object"
},
"Profile": {
"description": "Properties specific to a unique profile.",
"additionalProperties": false,
"type": "object",
"properties": {
"acrylicOpacity": {
"default": 0.5,
@@ -2627,7 +2558,7 @@
},
"backgroundImage": {
"description": "Sets the file location of the image to draw over the window background.",
"anyOf": [
"oneOf": [
{
"type": [
"string",
@@ -2639,6 +2570,10 @@
"desktopWallpaper"
]
}
],
"type": [
"string",
"null"
]
},
"backgroundImageAlignment": {
@@ -2975,7 +2910,8 @@
"description": "When set to true, the window will have an acrylic material background. When set to false, the window will have a plain, untextured background.",
"type": "boolean"
}
}
},
"type": "object"
},
"ProfileList": {
"description": "A list of profiles and the properties specific to each.",
@@ -2990,7 +2926,6 @@
},
"ProfilesObject": {
"description": "A list of profiles and default settings that apply to all of them",
"type": "object",
"properties": {
"list": {
"$ref": "#/$defs/ProfileList"
@@ -2999,12 +2934,12 @@
"description": "The default settings that apply to every profile.",
"$ref": "#/$defs/Profile"
}
}
},
"type": "object"
},
"SchemeList": {
"description": "Properties are specific to each color scheme. ColorTool is a great tool you can use to create and explore new color schemes. All colors use hex color format.",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
@@ -3093,7 +3028,8 @@
"$ref": "#/$defs/Color",
"description": "Sets the color used as ANSI yellow."
}
}
},
"type": "object"
},
"type": "array"
}
@@ -3103,7 +3039,6 @@
"$ref": "#/$defs/Globals"
},
{
"type": "object",
"additionalItems": true,
"properties": {
"profiles": {

View File

@@ -115,7 +115,7 @@ Incoming issues/asks/etc. are triaged several times a week, labeled appropriatel
[Up Next]: https://github.com/microsoft/terminal/milestone/37
[Backlog]: https://github.com/microsoft/terminal/milestone/45
[Terminal v2 Roadmap]: ./terminal-v2-roadmap.md
[Terminal v2 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/terminal-v2-roadmap.md
[Windows Terminal Preview 1.2 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-2-release/
[Windows Terminal Preview 1.3 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-3-release/
@@ -131,4 +131,4 @@ Incoming issues/asks/etc. are triaged several times a week, labeled appropriatel
[Windows Terminal Preview 1.13 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-13-release/
[Windows Terminal Preview 1.14 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-14-release/
[Terminal 2023 Roadmap]: ./roadmap-2023.md
[Terminal 2023 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/roadmap-2023.md

View File

@@ -54,9 +54,9 @@ _informative, not normative_
For a more fluid take on what each of the team's personal goals are, head on over to [Core team North Stars]. This has a list of more long-term goals that each team member is working towards, but not things that are necessarily committed work.
[^1]: A conclusive list of these features can be found at [../src/features.xml](../src/features.xml). Note that this is a raw XML doc used to light up specific parts of the codebase, and not something authored for human consumption.
[^1]: A conclusive list of these features can be found at https://github.com/microsoft/terminal/blob/main/src/features.xml. Note that this is a raw XML doc used to light up specific parts of the codebase, and not something authored for human consumption.
[2022 Roadmap]: ./roadmap-2022.md
[2022 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/roadmap-2022.md
[Terminal 1.17]: https://github.com/microsoft/terminal/releases/tag/v1.17.1023
[Terminal 1.18]: https://github.com/microsoft/terminal/releases/tag/v1.18.1462.0

View File

@@ -435,7 +435,7 @@ ultimately deemed it to be out of scope for the initial spec review.
<!-- Footnotes -->
[#2046]: https://github.com/microsoft/terminal/issues/2046
[Command Palette, Addendum 1]: ../%232046%20-%20Unified%20keybindings%20and%20commands%2C%20and%20synthesized%20action%20names.md
[Command Palette, Addendum 1]: https://github.com/microsoft/terminal/blob/main/doc/specs/%232046%20-%20Unified%20keybindings%20and%20commands%2C%20and%20synthesized%20action%20names.md
[#3337]: https://github.com/microsoft/terminal/issues/3337
[#6899]: https://github.com/microsoft/terminal/issues/6899

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 KiB

View File

@@ -1,744 +0,0 @@
---
author: Mike Griese
created on: 2022-08-22
last updated: 2023-08-03
issue id: 1595
---
# Windows Terminal - Suggestions UI
## Abstract
Multiple related scenarios have come up where it would be beneficial to display
actionable UI to the user within the context of the active terminal itself. This
UI would be akin to the Intellisense UI in Visual Studio. It appears right where
the user is typing, and can help provide immediate content for the user, based
on some context. The "Suggestions UI" is this new ephemeral UI within the
Windows Terminal that can display different types of actions, from different
sources.
## Background
The Suggestions UI is the singular UI by which the Terminal can display a
variety of suggestions to the user. These include:
* Recent commands the user has executed in this terminal, powered by shell integration.
* Recent directories, similarly powered by shell integration
* Completions from the shell itself (like the shell completions in PowerShell)
* Tasks, which are `sendInput` actions from the user's settings
* Buffer Completions, which is a dumb type of autocomplete based on words in the buffer
* and more (as provided via extensions)
All of these scenarios are places where it makes sense to present the user a
menu at the point of text insertion in the terminal control itself.
### Inspiration
Primarily, the inspiration is any Intellisense-like experience, in any app.
Visual Studio, VsCode, PowerShell, vim, Sublime any JetBrains IDE - there's more
than enough examples in the wild.
Ultimately, the inspiration for the Suggestions UI came from a bunch of places
all at once. In the course of a few months though, it became clear that we'd
need a unified UI for displaying a variety of suggestion-like experiences in the
Terminal. Our work with the PowerShell and VsCode teams helped refine these
requests all into the unified design below.
### User Stories
Size | Description
-----------|--
🐣 Crawl | The user can bring up the Suggestions UI with recent commands, powered by shell integration
🐣 Crawl | [#12863] The user can bring up the Suggestions UI with recent directories, powered by shell integration
🚶 Walk | The user can bring up the Suggestions UI with tasks from their settings
🚶 Walk | CLI apps can invoke the Suggestions UI with a new VT sequence
🚶 Walk | The Suggestions UI can be opened using the current typed commandline as a filter
🚶 Walk | Recent commands and directories are stored in `state.json`, across sessions
🏃‍♂️ Run | Suggestions can have descriptions presented in / alongside the UI
🏃‍♂️ Run | The Suggestions UI can be opened without any nesting
🏃‍♂️ Run | The Suggestions UI can be opened, nested by `source` of the suggestion
🚀 Sprint | Extensions can provide suggestion sources for the Suggestions UI
🚀 Sprint | The Suggestions UI can be opened in "inline" mode, only showing the text of the first suggestion
### Elevator Pitch
The Suggestions UI is a UI element displayed in the Terminal for providing
different types of text suggestions to the user - anything from recently run
commands, to saved commands, to tab-completion suggestions from the shell
itself.
## Business Justification
It will delight developers.
Furthermore, our partners on the Visual Studio team have been requesting similar
functionality for some time now. The way autocompletion menus in PowerShell
currently interact with UIA clients leaves much to be desired. They'd like a way
to provide richer context to screen readers. Something to enable the terminal to
more specifically describe the context of what's being presented to the user.
## Scenario Details
### UI/UX Design
#### Prototypes
The following gif was a VsCode prototype of [shell-driven autocompletion]. This
is the point of reference we're starting from when talking about what the
suggestions UI might look like.
![](vscode-shell-suggestions.gif)
These suggestions are populated by logic within PowerShell itself, and
communicated to the Terminal. The Terminal can then display them in the
Suggestions UI.
The following demonstrate a prototype of what that might look like for the
Terminal. These are meant to be informative, not normative, representations of
what the UI would look like.
![](shell-autocomplete-july-2022-000.gif)
A prototype of the recent commands UI, powered by shell integration:
![](command-history-suggestions.gif)
A prototype of the tasks UI, powered by the user's settings:
![](tasks-suggestions.gif)
(admittedly, the `TeachingTip` in that gif is a prototype and was later replaced
with a better version.)
In general, the Suggestions UI will present a list of elements to select from,
near the text cursor. This control might be contain a text box for filtering
these items (a "**palette**"), or it might not (a "**menu**").
![An example of the menu mode](3121-suggestion-menu-2023-000.gif)
#### Palette vs Menu
Depending on how the suggestions UI is invoked, we may or may not want to
display a text box for filtering these suggestions. Consider the Intellisense
menu in Visual Studio. That's a UI that only allows for up/down for navigation
(and enter/tab for selecting the suggestion).
For suggestions driven by the Terminal, we'll display a filtering text box in
the Suggestions UI. This is similar to the command palette's search - a fuzzy
search to filter the contents. This is the "**palette**" style of the
suggestions dialog.
For completions driven by the shell, we should probably not display the
filtering text box. This is the "**menu**" style of the suggestion dialog. The
user is primarily interacting with the shell here, not the Terminal.
> **Warning**
> TODO! For discussion, possibly with a real UX designer.
How should we handle completions here? Tab? Enter? Right-Arrow? Should we have
an element selected when we open the menu, or should tab/enter only work once
the user has used the arrows at least once? Sublime allows for <kbd>tab</kbd> to
complete the suggestion immediately.
Consider also that these suggestions might be provided by the shell, as the user
is typing at a commandline shell. For something like PowerShell, the user might
want to start typing a command and have it tab-complete based off the shell's
tab expansion rules. PowerShell's inline suggestions use right-arrow to
differentiate "use this suggestion" vs tab for "tab expand what I'm typing at
the prompt". We should probably preserve this behavior.
We probably don't want to provide different experiences for the **menu** version
of the Suggestions UI vs. the **palette** version. In the palette version, the
user won't be pressing tab to tab-complete at the shell - the focus is out of
the of terminal and in the Suggestions UI. With the menu version, the focus is
still "in the terminal", and users would expect tab to tab-complete.
We will want to make sure that there's some semblance of consistency across our
implementation for the Suggestions UI, our own Command Palette, VsCode's
intellisense and their own implementation of shell-completions in the Terminal.
> **Note**
> In my prototype, for the "Menu" mode, I accepted ALL of right-arrow, tab, and
> enter as "accept completion", and any other key dismissed the UI. This _felt_
> right for that mode. I'm not sure we could make the same call for "palette"
> mode, where we'd need tab for navigating focus.
### Implementation Details
#### Fork the Command Palette
We're largely going to start with the Command Palette to build the Suggestions
UI[[1](#footnote-1)]. The Command Palette is already a control we've built for displaying a
transient list of commands and dispatching them to the rest of the app.
Currently, the Command Palette is a single static control, at the top-center of
the Terminal window, and occupying a decent portion of the screen. For the
Suggestions UI, we'll instead want to make sure that the control appears
relative to the current cursor position.
We'll start by taking the command palette, and copying it over to a new control.
This will allow us to remove large chunks of code dealing with different modes
(i.e. the tab switcher), and code dealing with prefix characters to switch
modes.
We'll need to make some small modifications to enable the Suggestions UI to
* work as a text cursor-relative control
* exist as a Flyout outside the bounds of the Terminal window
* If the Suggestions UI is too close to the bottom of the screen, we'll need it to open
"upwards", with the search box at the _bottom_ and the list extending above it
* prevent it from switching to command-line mode
* display tooltips / `TeachingTip`s / some secondary flyout with a description
of the suggestion (if provided)
#### Completion sources
The Suggestions UI will support suggestions from a variety of different
"sources". As an example, consider the following actions:
```json
{ "command": { "action":"suggestions", "source": "commandHistory" } },
{ "command": { "action":"suggestions", "source": "directoryHistory" } },
{ "command": { "action":"suggestions", "source": "tasks" } },
{ "command": { "action":"suggestions", "source": "local" } },
{ "command": { "action":"suggestions", "source": ["local", "tasks", "commandHistory"] } },
{ "command": { "action":"suggestions", "source": "Microsoft.Terminal.Extensions.BufferComplete" } },
```
Each of these `suggestions` actions would open the Suggestions UI with a
different set of actions.
* `commandHistory`: Use commands from this session, as identified via shell
integration. This won't be able to return any suggestions if the user has not
configured their shell to support shell integration sequences yet.
* `directoryHistory`: Populate the list with a series of `cd {path}` commands,
where the paths are populated via shell integration. Paths are in MRU order.
* `tasks`: Populate the list with all `sendInput` actions in the user's settings
file. The command structure should remain unchanged. For example, if they have
`sendInput` actions nested under a "git" command, then the "git" entry will
remain in this tasks view with their `sendInput` actions nested inside it. For
more details, see the [Tasks] spec.
* `local`: Populate the list with tasks that are located in the CWD, in a file
named `.wt.json`. For more details, see the [Tasks] spec.
* `Microsoft.Terminal.Extensions.BufferComplete`: As an example, this
demonstrates how an action might be authored to reference a suggestion source
from an extension[[2](#footnote-2)].
Each of these different sources will build a different set of `Command`s,
primarily populated with `sendInput` actions. We'll load those `Command`s into
the Suggestions UI control, and open it at the text cursor.
To drill in on a single example - the `commandHistory` source. In that
particular case, the TerminalPage will query the active TermControl for a list
of its recent commands. If it knows these (via shell integration), then the
TerminalPage will use that list of commands to build a list of `sendInput`
actions. Those will then get fed to the suggestions UI.
Not listed above is [shell-driven autocompletion]. These aren't something that
the Terminal can invoke all on its own - these are something the shell would
need to invoke themselves.
#### Pre-populate the current commandline context
Consider the following scenario. A user has typed `git c` in their shell, and
has [shell integration] enabled for their shell. They want to open the
Suggestions UI filtered to their recent history, but starting with what they've
already typed. To support this scenario, we'll add an additional property:
* `"useCommandline"`: `bool` (**default**: `true`)
* `true`: the current commandline the user has typed will pre-populate the
filter of the Suggestions UI. This requires that the user has enabled shell
integration in their shell's config.
* `false`: the filter will start empty, regardless of what the user has typed.
With that setting, the user can achieve their desired UX with the following action:
```json
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true } },
```
Now, when they type `git c` and invoke the Suggestions UI, they can immediately
start searching for recent commands that started with `git c`.
The primary use case for `useCommandline: false` was for `"nesting": "source"`.
When filtering a list of ["Tasks...", "Recent commands...", "Recent
directories...", "Docker...", "Git..."], then there's minimal value to start by
filtering to "git c".
#### Default actions
I propose adding the following actions to the Terminal by default:
```json
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true } },
{ "command": { "action":"suggestions", "source": "directoryHistory" } },
{ "command": { "action":"suggestions", "source": ["local", "tasks", "commandHistory"], "useCommandline": true, "nesting": "disabled" } },
{ "command": { "action":"suggestions", "source": ["all"], "useCommandline": false, "nesting": "source" } },
```
These actions are colloquially:
* Give me suggestions from my recent commands, using what I've typed
* Give me suggestions of directories I've recently been in
* _(After [Tasks] are implemented)_ Give me suggestions from recent commands,
commands I've saved, and commands for this project. Don't nest any, so they're
all in the top-level menu. Use what I've typed already to start filtering.
* Just open the Suggestions UI with all suggestions sources, and group them by
the source of the suggestions.
This should cover most of the basic use cases for suggestions.
#### Who owns this menu?
There was some discussion of who should own the suggestions menu. The control
itself? Or the app hosting the control?
A main argument for hosting this UI in the control itself is that any consumer
of the `TermControl` should be able to display the [shell-driven autocompletion]
menu. And they should get the UI from us "for free". Consumers shouldn't need to
reimplement it themselves. This probably could be done without many changes:
* Instead of operating on `Command`s and actions from the terminal settings,
the control could just know that all the entries in the menu are "send
input" "actions".
* The control could offer a method to manually invoke the Suggestions UI for a
list of {suggestion, name, description} objects.
* The app layer could easily translate between sendInput actions and these
pseudo-actions.
A big argument in favor of having the app layer host the control: Consider an
app like Visual Studio. When they embed the control, they'll want to style the
shell-completions UI in their own way. They already have their own intellisense
menu, and their own UI paradigm.
For now, we'll leave this as something that's owned by the app layer. When we
get around to finalizing the [shell-driven autocompletion] design, we can
iterate on ideas for supporting both consumers that want to use a pre-built
suggestions control, or consumers who want to bring their own.
## Tenets
<table>
<tr><td><strong>Compatibility</strong></td><td>
This shouldn't break any existing flows. This is a general purpose UI element,
to be extended in a variety of ways. Those customizations will all be opt-in by
the user, so I'm not expecting any breaking compatibility changes here.
</td></tr>
<tr><td><strong>Accessibility</strong></td><td>
The Suggestions UI was designed with the goal of making commandline shell
suggestions _more_ accessible. As Carlos previously wrote:
> Screen readers struggle with this because the entire menu is redrawn every time, making it harder to understand what exactly is "selected" (as the concept of selection in this instance is a shell-side concept represented by visual manipulation).
>
> ...
>
> _\[Shell driven suggestions\]_ can then be leveraged by Windows Terminal to create UI elements. Doing so leverages WinUI's accessible design.
This will allow the Terminal to provide more context-relevant information to
screen readers.
</td></tr>
<tr><td><strong>Sustainability</strong></td><td>
No sustainability changes expected.
</td></tr>
<tr><td><strong>Localization</strong></td><td>
The localization needs of the Suggestions UI will be effectively the same as the
needs of the Command Palette.
The Terminal will have no way to localize suggestions that are provided via
[shell-driven autocompletion]. These are just verbatim strings that the shell
told us to use. We don't consider this to be something to worry about, however.
This is no different than the fact that Terminal cannot localize the `Get-Help`
(or any other) output of PowerShell.
</td></tr>
</table>
## Implementation Plan
This is more of an informative outline, rather than a normative one. Many of the
things from Crawl, Walk, and Run are all already in PRs as of the time of this
spec's review.
### 🐣 Crawl
* [ ] Fork the Command palette to a new UI element, the `SuggestionsControl`
* [ ] Enable previewing `sendInput` actions in the Command Palette and `SuggestionsControl`
* [ ] Enable the `SuggestionsControl` to open top-down (aligned to the bottom of the cursor row) or bottom-up (aligned to the top of the cursor row).
* [ ] Disable sorting on the `SuggestionsControl` - elements should presumably be pre-sorted by the source.
* [ ] Expose the recent commands as a accessor on `TermControl`
* [ ] Add a `suggestions` action which accepts a single option `recentCommands`. These should be fed in MRU order to the `SuggestionsControl`.
* [ ] Expose the recent directories as an accessor on `TermControl`, and add a `recentDirectories` source.
### 🚶 Walk
* [ ] Add a `tasks` source to `suggestions` which opens the Suggestions UI with
a tree of all `sendInput` commands
* [ ] Enable the `SuggestionsControl` to open with or without a search box
* [ ] Plumb support for shell-driven completions through the core up to the app
* [ ] Expose the _current_ commandline from the `TermControl`
* [ ] Add a `useCommandline` property to `suggestions`, to pre-populate the search with the current commandline.
* [ ] Persist recent commands / directories accordingly
### 🏃‍♂️ Run
* [ ] Add a `description` field to `Command`
* [ ] Add a `TeachingTip` (or similar) to the Suggestions UI to display
descriptions (when available)
* [ ] Use the `ToolTip` property of shell-driven suggestions as the description
* [ ] Add a boolean `nesting` property which can be used to disable nesting on the `tasks` source.
* [ ] Add the ability for `nesting` to accept `enabled`/`disabled` as `true`/`false` equivalents
* [ ] Add the ability for `nesting` to accept `source`, which instead groups all
commands to the Suggestions UI by the source of that suggestion.
### 🚀 Sprint
The two "sprint" tasks here are much more ambitious than the other listed
scenarios, so breaking them down to atomic tasks sees less reasonable. We'd have
to spend a considerable amount more time figuring out _how_ to do each of these
first.
For example - extensions. We have yet to fully realize what extensions _are_.
Determining how extensions will provide suggestions is left as something we'll
need to do as a part of the Extensions spec.
## Conclusion
Here's a sample json schema for the settings discussed here.
```json
"OpenSuggestionsAction": {
"description": "Arguments corresponding to a Open Suggestions Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "suggestions"
},
"source": {
"$ref": "#/$defs/SuggestionSource",
"description": "Which suggestion sources to filter."
},
"useCommandline": {
"default": false,
"description": "When set to `true`, the current commandline the user has typed will pre-populate the filter of the Suggestions UI. This requires that the user has enabled shell integration in their shell's config. When set to false, the filter will start empty."
},
"nesting": {
"default": true,
"description": "When set to `true`, suggestions will follow the provided nesting structure. For Tasks, these will follow the structure of the Command Palette. When set to `false`, no nesting will be used (and all suggestions will be in the top-level menu.",
"$comment": "This setting is a possible follow-up setting, not required for v1. "
}
}
}
]
},
"BuiltinSuggestionSource": {
"enum": [
"commandHistory",
"directoryHistory",
"tasks",
"local",
"all"
],
"type": "string"
},
"SuggestionSource": {
"default": "all",
"description": "Either a single suggestion source, or an array of sources to concatenate. Built-in sources include `commandHistory`, `directoryHistory`, `tasks`, and `local`. Extensions may provide additional values. The special value `all` indicates all suggestion sources should be included",
"$comment": "`tasks` and `local` are sources that would be added by the Tasks feature, as a follow-up"
"oneOf": [
{
"type": [ "string", "null", "BuiltinSuggestionSource" ]
},
{
"type": "array",
"items": { "type": "BuiltinSuggestionSource" }
},
{
"type": "array",
"items": { "type": "string" }
}
]
},
```
### Future Considerations
* Another extension idea: `WithFig.FigCompletions`. Imagine an extension that
could parse existing [Fig] completion specs, and provide those as suggestions
in this way.
* This might be a good example of an async suggestion source. The current
commandline is used as the starting filter, and the suggestions would be
populated by some `fig` process / thread / async operation that returns the
suggestions.
* If the user hasn't enabled shell completion, we could add text to the
`commandHistory` or `directoryHistory` menus to inform the user how they could
go enable shell integration. We already have a docs page dedicated to this, so
we could start by linking to that page. More notes on this in [Automatic shell
integration](#Automatic-shell-integration).
* Maybe there could be a per-profile setting for automatic suggestions after
some timeout. Like, as you type, a menu version of the Suggestions UI appears.
So you could just start typing `git c`, and it would automatically give you a
menu with suggestions, implicitly using the typed command as the "filter".
* Maybe we could do this as an `implicit` property on the `suggestions` action
#### Description Tooltips
> **Note**: _This is left as a future consideration for the initial draft of
> this spec. I'd like to flesh out [shell-driven autocompletion] more before
> committing any plans here._
It would be beneficial for the Suggestions UI to display additional context to
the user. Consider a extension that provides some commands for the user, like a
hypothetical "Docker" extension. The extension author might be able to give the
commands simplified names, but also want to expose a more detailed description
of the commands to the user.
Or consider the Suggestions UI when invoked by [shell-driven autocompletion].
The shell might want to provide help text to the user with each of the
suggestions. This would allow a user to browse through the suggestions that they
might not know about, and learn how they work before committing to one.
Only the help text for the currently hovered command should be presented to the
user. To support this kind of UX, we'll add an optional flyout of some sort to
display with the Suggestions UI. This flyout will only appear if there's more
information provided to the Terminal.
This might be in the form of a `TeachingTip`, as in this example:
![TeachingTip with description](https://user-images.githubusercontent.com/18356694/222244568-243a6482-92d9-4c3c-bffc-54ad97f01f69.gif)
Actions in the settings could also accept an optional `description` property, to
specify the string that would be presented in that flyout.
#### Automatic shell integration
A large portion of these features all rely on shell integration being enabled by
the user. However, this is not a trivial thing for the Terminal to do on behalf
of the user. Shell integration relies on changes to the user's shell config. If
the Terminal were to try and configure those itself, we may accidentally destroy
configuration that the user has already set up. Hence why the Terminal can't
just have a "Light up all the bells and whistles" toggle in the Settings UI.
This is a non-trivial problem to solve, so it is being left as a future
consideration, for a later spec. It deserves its own spec to sort out how we
should expose this to users and safely implement it.
#### Pre-filtering the UI & filter by source
> **Note**: _This is a brainstorm I considered while writing this spec. I would
> not include it in the v1 of this spec. Rather, I'd like to leave it for
> where we might go with this UX in the future._
Do want to support different _types_ of nesting? So instead of just the default,
there could be something like `nesting: "source"`, to create a menu structured
like:
```
Suggestions UI
├─ Recent Commands...
│ ├─ git checkout main
│ ├─ git fetch
│ └─ git pull
├─ Recent Directories...
│ ├─ d:\dev
│ ├─ d:\dev\public
│ └─ d:\dev\public\terminal
├─ Saved tasks...
│ ├─ Git...
│ │ └─ git commit -m "
│ │ └─ git log...
│ └─ bx & runut
└─ Docker
├─ docker build --platform linux/amd64 <path>
└─ docker logs -f --tail <lines_count> <container_name>
```
> **Note**
> I'm using `Docker` as an example fragment extension that provides
> some `docker` commands. When grouping by `"source"`, we could pull those into
> a separate top-level entry. When not grouping by `"source"`, those would still
> show up with the rest of `tasks`. )
#### Store recent commands across sessions
> **Note**
> _I'm not sure we really want to put this in this spec or not, hence
> why it is in the "Future considerations" section. I think it is worth
> mentioning. This might be better served in the [shell integration] doc._
We'll probably want a way for recent commands to be saved across sessions. That way, your `cmd.exe` command history could persist across sessions. We'd need:
* A setting to enable this behavior
* A setting to control the context of these saved commandlines.
* Do we want them saved per-profile, or globally?
* If they're saved per-profile, maybe a profile can opt-in to loading all the commands?
* How does defterm play with this? Do we "layer" by concatenating per-profile commands with `profiles.defaults` ones?
* A button in the Settings UI for clearing these commands
* Should fragments be able to pre-populate "recent commands"?
* I'm just gonna say _no_. That would be a better idea for Tasks (aka just a `sendInput` Action that we load from the fragment normally as a Task), or a specific suggestion source for the fragment extension.
#### Inline mode
> **Note**
> _This is a half-baked idea with some potential. However, I don't
> think it needs to be a part of the v1 of the Suggestions UI, so I'm leaving it
> under future considerations for a future revision._
Do we want to have a suggestions UI "mode", that's just **one** inline
suggestion, "no" UI? Some UX ala the `PsReadline` recent command suggestion
feature. Imagine, we just display the IME ghost text thing for the first result,
given the current prompt?
Take the following action as an example:
```json
{ "command": { "action":"suggestions", "source": "commandHistory", "useCommandline": true, "inline": true } },
```
Type the start of some command at the prompt, and press that key. Presto, we do
the `pwsh` thing. Ghost text appears for the first match in the `commandHistory`
for what the user has typed. If they press another key, ~they've typed into the
"hidden" Suggestions UI, which filters the (hidden) list more, and updates the
one inline suggestion.~
Or, instead, typed keys go to the shell, and then we re-query the commandline,
and update the filter accordingly. That would allow tab-completion to still
work. We'd use <kbd>right arrow</kbd> to accept the suggestion (and dismiss the
ghost text preview).
This would seemingly SUPER conflict with PowerShell's own handler. Probably not
something someone should enable for PowerShell 7 profiles if they're using that
feature.
### Rejected ideas
These are musings from earlier versions of the spec.
* **Asynchronous prompting**: This was rejected because it was so fundamentally
different from the rest of the UX of the Suggestions UI, it didn't make sense
to try and also do that behavior.
* ...
#### REJECTED: Asynchronous prompting
Certain suggestion sources might want to provide results asynchronously.
Consider a source that might want to make a web request to populate what strings
to suggest. That source might want to prompt the user for input first, then
dispatch the request, then populate the UI. Or something like a `fig`-like
suggestion source, which would need to parse some files from the disk to
generate the list of suggestions.
The easiest way to do this would be to provide a secondary UI element for
prompting the user for input, doing the request in the background, then opening
the UI later. However, that feels a little disjointed. Could we instead provide
a more continuous experience?
The following is a proposal for using the Suggestions UI itself as the control
to prompt the user for input.
```c++
TerminalPage::SetUpSuggestionsUI()
{
const auto& asyncSource{ AsyncSuggestions() };
suggestionsUI.OnInputChanged({ asyncSource, AsyncSuggestions::InputChangedHandler});
// In this example, we don't want the UI to filter item based on the input
// string - the source has already determined the list of relevant matches.
suggestionsUI.FilterByInput(false);
asyncSource.SuggestionsChanged([](const auto& newCommands){
suggestionsUI.Loading(false);
suggestionsUI.Commands(newCommands);
})
}
void AsyncSuggestions::InputChangedHandler(FilterChangedArgs args)
{
// kick off a trailing ThrottledFunc to do a new query
_loadNewResults->Run(args.NewInputText());
// If we get another request, we might want to cancel the pending throttled
// func entirely, and start the timeout fresh. Just so that we only make a
// query for the final string they type.
args.RequestLoading(true); // pass a boolean back up in the args, so that
// the Suggestions UI can clear out the current commands, and start displaying an
// indeterminate progress wheel.
}
```
That would basically _have_ to be special cased for this source, at least for
now. We could refactor that later to better deal with extensions.
Let's make sure this would work for something `fig`-like, where the "prompt" is
literally the prompt, what the user has already typed at the commandline.
After some discussion:
* How do we differentiate the prompting version of the Suggestions UI from the
filtering version?
* The prompting version _doesn't_ filter results
* Async modes wouldn't work with sync ones at all. E.g. if you did `source:
["tasks", "myAsyncSource"]`. It doesn't make sense to start with a list of
`tasks`, then type, find no tasks, but then oh! the UI fills in some other
suggestions too. That's weird.
## Resources
These are some other work streams that have a lot of tie-in to the Suggestions
UI. These are all being spec'd at roughly the same time, so links may not be
fully up to date.
* [Shell integration]
* [Shell-driven autocompletion]
* [Tasks]
### Footnotes
<a name="footnote-1"><a>[1]: We've had discussion in the past ([#7285]) about
possibly creating a more abstract "Live filtering list view" to replace the
Command Palette. We could most certainly use that here too. We've decided to
initially go with a fork for now.
<a name="footnote-2"><a>[2]: Obviously, we're not having a real discussion about
extensions in this doc. This example is solely to show that there's room for
extensions to work with the "source" property in this design. What the final
shape of extensions will be is very much still to be determined.
[Fig]: https://github.com/withfig/autocomplete
[Warp]: https://www.warp.dev/
[workflows]: https://docs.warp.dev/features/workflows
[also working on workflows]: https://fig.io/user-manual/workflows
[winget script]: https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
[#1595]: https://github.com/microsoft/terminal/issues/1595
[#7039]: https://github.com/microsoft/terminal/issues/7039
[#3121]: https://github.com/microsoft/terminal/issues/3121
[#10436]: https://github.com/microsoft/terminal/issues/10436
[#12927]: https://github.com/microsoft/terminal/issues/12927
[#12863]: https://github.com/microsoft/terminal/issues/12863
[#7285]: https://github.com/microsoft/terminal/issues/7285
[#14939]: https://github.com/microsoft/terminal/issues/7285
[#keep]: https://github.com/zadjii/keep
[VsCode Tasks]: ../../../.vscode/tasks.json
<!-- Note: This is its own spec in progress, but for the time being #12862 will do -->
[Tasks]: https://github.com/microsoft/terminal/issues/12862
<!-- Note: This is just a link to the PR that introduced the shell integration spec -->
[shell integration]: https://github.com/microsoft/terminal/pull/14792
<!-- Note: If I ever write a spec for this, go ahead and replace this link -->
[shell-driven autocompletion]: https://github.com/microsoft/terminal/issues/3121

Binary file not shown.

Before

Width:  |  Height:  |  Size: 965 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 KiB

View File

@@ -605,4 +605,4 @@ as well as 3 schemes: "Scheme 1", "Scheme 2", and "Scheme 3".
<!-- Footnotes -->
[Command Palette Spec]: ./%232046%20-%20Command%20Palette.md
[Command Palette Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%232046%20-%20Command%20Palette.md

View File

@@ -612,8 +612,8 @@ You could have a profile that layers on an existing profile, with elevated-speci
[#8514]: https://github.com/microsoft/terminal/issues/8514
[#10276]: https://github.com/microsoft/terminal/issues/10276
[Process Model 2.0 Spec]: ../%235000%20-%20Process%20Model%202.0.md
[Configuration object for profiles]: ../%233062%20-%20Appearance configuration object for profiles.md
[Session Management Spec]: ./%234472%20-%20Windows%20Terminal%20Session%20Management.md
[Process Model 2.0 Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%235000%20-%20Process%20Model%202.0.md
[Configuration object for profiles]: https://github.com/microsoft/terminal/blob/main/doc/specs/Configuration%20object%20for%20profiles.md
[Session Management Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%234472%20-%20Windows%20Terminal%20Session%20Management.md
[The Old New Thing: How can I launch an unelevated process from my elevated process, redux]: https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443
[Workspace Trust]: https://code.visualstudio.com/docs/editor/workspace-trust

View File

@@ -559,4 +559,4 @@ runtime.
[Tab Tear-out in the community toolkit]: https://github.com/windows-toolkit/Sample-TabView-TearOff
[Quake mode scenarios]: https://github.com/microsoft/terminal/issues/653#issuecomment-661370107
[`ISwapChainPanelNative2::SetSwapChainHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/windows.ui.xaml.media.dxinterop/nf-windows-ui-xaml-media-dxinterop-iswapchainpanelnative2-setswapchainhandle
[Process Model 2.0 Spec]: ./doc/specs/%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
[Process Model 2.0 Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md

View File

@@ -730,7 +730,7 @@ user to differentiate between the two behaviors.
[#5727]: https://github.com/microsoft/terminal/issues/5727
[#9992]: https://github.com/microsoft/terminal/issues/9992
[Process Model 2.0 Spec]: ../%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
[Process Model 2.0 Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%235000%20-%20Process%20Model%202.0/%235000%20-%20Process%20Model%202.0.md
[Quake 3 sample]: https://youtu.be/ZmR6HQbuHPA?t=27
[`RegisterHotKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey
[`dev/migrie/f/653-QUAKE-MODE`]: https://github.com/microsoft/terminal/tree/dev/migrie/f/653-QUAKE-MODE

View File

@@ -215,8 +215,8 @@ actions manually.
the tab context menu or the control context menu.
<!-- Footnotes -->
[Command Palette Spec]: ./doc/specs/%232046%20-%20Command%20Palette.md
[New Tab Menu Customization Spec]: ./doc/specs/%231571%20-%20New%20Tab%20Menu%20Customization.md
[Command Palette Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%232046%20-%20Command%20Palette.md
[New Tab Menu Customization Spec]: https://github.com/microsoft/terminal/blob/main/doc/specs/%231571%20-%20New%20Tab%20Menu%20Customization.md
[#1571]: https://github.com/microsoft/terminal/issues/1571
[#1912]: https://github.com/microsoft/terminal/issues/1912

View File

@@ -290,7 +290,7 @@ though. **I recommend we ignore this for now, and leave this as a follow-up**.
For reference, refer to the following from iTerm2:
![image](https://user-images.githubusercontent.com/2578976/64075757-fa971980-ccee-11e9-9e44-47aaf3bca76c.png)
We don't have a menu bar like on macOS, but we do have a tab context menu. We
We don't have a menu bar like on MacOS, but we do have a tab context menu. We
could add these items as a nested entry under each tab. If we wanted to do this,
we should also make sure to dynamically change the icon of the MenuItem to
reflect the current broadcast state.

View File

@@ -373,7 +373,7 @@ changes, or the active pane in a tab changes:
`TabRowControl` to match.
The `tab.cornerRadius` might be a bit trickier to implement. Currently, there's
no XAML resource that controls this, nor is this something that's exposed by
not a XAML resource that controls this, nor is this something that's exposed by
the TabView control. Fortunately, this is something that's exposed to us
programmatically. We'll need to manually set that value on each `TabViewItem` as
we create new tabs. When we reload settings, we'll need to make sure to come

View File

@@ -142,4 +142,4 @@ Feature Notes:
[#4472]: https://github.com/microsoft/terminal/issues/4472
[#8048]: https://github.com/microsoft/terminal/pull/8048
[Terminal 2022 Roadmap]: ./roadmap-2022.md
[Terminal 2022 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/roadmap-2022.md

View File

@@ -111,28 +111,6 @@ const til::point_span* Search::GetCurrent() const noexcept
return nullptr;
}
void Search::HighlightResults() const
{
std::vector<til::inclusive_rect> toSelect;
const auto& textBuffer = _renderData->GetTextBuffer();
for (const auto& r : _results)
{
const auto rbStart = textBuffer.BufferToScreenPosition(r.start);
const auto rbEnd = textBuffer.BufferToScreenPosition(r.end);
til::inclusive_rect re;
re.top = rbStart.y;
re.bottom = rbEnd.y;
re.left = rbStart.x;
re.right = rbEnd.x;
toSelect.emplace_back(re);
}
_renderData->SelectSearchRegions(std::move(toSelect));
}
// Routine Description:
// - Takes the found word and selects it in the screen buffer
@@ -149,7 +127,6 @@ bool Search::SelectCurrent() const
return true;
}
_renderData->ClearSelection();
return false;
}

View File

@@ -33,7 +33,6 @@ public:
void FindNext() noexcept;
const til::point_span* GetCurrent() const noexcept;
void HighlightResults() const;
bool SelectCurrent() const;
const std::vector<til::point_span>& Results() const noexcept;

View File

@@ -126,6 +126,8 @@ void TextBuffer::_reserve(til::size screenBufferSize, const TextAttribute& defau
// The compiler doesn't understand the likelihood of our branches. (PGO does, but that's imperfect.)
__declspec(noinline) void TextBuffer::_commit(const std::byte* row)
{
assert(row >= _commitWatermark);
const auto rowEnd = row + _bufferRowStride;
const auto remaining = gsl::narrow_cast<uintptr_t>(_bufferEnd - _commitWatermark);
const auto minimum = gsl::narrow_cast<uintptr_t>(rowEnd - _commitWatermark);
@@ -146,7 +148,7 @@ void TextBuffer::_decommit() noexcept
_commitWatermark = _buffer.get();
}
// Constructs ROWs up to (excluding) the ROW pointed to by `until`.
// Constructs ROWs between [_commitWatermark,until).
void TextBuffer::_construct(const std::byte* until) noexcept
{
for (; _commitWatermark < until; _commitWatermark += _bufferRowStride)
@@ -158,8 +160,7 @@ void TextBuffer::_construct(const std::byte* until) noexcept
}
}
// Destroys all previously constructed ROWs.
// Be careful! This doesn't reset any of the members, in particular the _commitWatermark.
// Destructs ROWs between [_buffer,_commitWatermark).
void TextBuffer::_destroy() const noexcept
{
for (auto it = _buffer.get(); it < _commitWatermark; it += _bufferRowStride)
@@ -168,9 +169,8 @@ void TextBuffer::_destroy() const noexcept
}
}
// This function is "direct" because it trusts the caller to properly wrap the "offset"
// parameter modulo the _height of the buffer, etc. But keep in mind that a offset=0
// is the GetScratchpadRow() and not the GetRowByOffset(0). That one is offset=1.
// This function is "direct" because it trusts the caller to properly
// wrap the "offset" parameter modulo the _height of the buffer.
ROW& TextBuffer::_getRowByOffsetDirect(size_t offset)
{
const auto row = _buffer.get() + _bufferRowStride * offset;
@@ -184,6 +184,7 @@ ROW& TextBuffer::_getRowByOffsetDirect(size_t offset)
return *reinterpret_cast<ROW*>(row);
}
// See GetRowByOffset().
ROW& TextBuffer::_getRow(til::CoordType y) const
{
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
@@ -197,6 +198,7 @@ ROW& TextBuffer::_getRow(til::CoordType y) const
}
// We add 1 to the row offset, because row "0" is the one returned by GetScratchpadRow().
// See GetScratchpadRow() for more explanation.
#pragma warning(suppress : 26492) // Don't use const_cast to cast away const or volatile (type.3).
return const_cast<TextBuffer*>(this)->_getRowByOffsetDirect(gsl::narrow_cast<size_t>(offset) + 1);
}
@@ -238,6 +240,9 @@ ROW& TextBuffer::GetScratchpadRow()
// Returns a row filled with whitespace and the given attributes, for you to freely use.
ROW& TextBuffer::GetScratchpadRow(const TextAttribute& attributes)
{
// The scratchpad row is mapped to the underlying index 0, whereas all regular rows are mapped to
// index 1 and up. We do it this way instead of the other way around (scratchpad row at index _height),
// because that would force us to MEM_COMMIT the entire buffer whenever this function is called.
auto& r = _getRowByOffsetDirect(0);
r.Reset(attributes);
return r;
@@ -902,15 +907,14 @@ til::point TextBuffer::GetLastNonSpaceCharacter(const Viewport* viewOptional) co
// If the X coordinate turns out to be -1, the row was empty, we need to search backwards for the real end of text.
const auto viewportTop = viewport.Top();
auto fDoBackUp = (coordEndOfText.x < 0 && coordEndOfText.y > viewportTop); // this row is empty, and we're not at the top
while (fDoBackUp)
// while (this row is empty, and we're not at the top)
while (coordEndOfText.x < 0 && coordEndOfText.y > viewportTop)
{
coordEndOfText.y--;
const auto& backupRow = GetRowByOffset(coordEndOfText.y);
// We need to back up to the previous row if this line is empty, AND there are more rows
coordEndOfText.x = backupRow.MeasureRight() - 1;
fDoBackUp = (coordEndOfText.x < 0 && coordEndOfText.y > viewportTop);
}
// don't allow negative results
@@ -1146,6 +1150,39 @@ void TextBuffer::Reset() noexcept
_initialAttributes = _currentAttributes;
}
void TextBuffer::ClearScrollback(const til::CoordType start, const til::CoordType height)
{
if (start <= 0)
{
return;
}
if (height <= 0)
{
_decommit();
return;
}
// Our goal is to move the viewport to the absolute start of the underlying memory buffer so that we can
// MEM_DECOMMIT the remaining memory. _firstRow is used to make the TextBuffer behave like a circular buffer.
// The start parameter is relative to the _firstRow. The trick to get the content to the absolute start
// is to simply add _firstRow ourselves and then reset it to 0. This causes ScrollRows() to write into
// the absolute start while reading from relative coordinates. This works because GetRowByOffset()
// operates modulo the buffer height and so the possibly-too-large startAbsolute won't be an issue.
const auto startAbsolute = _firstRow + start;
_firstRow = 0;
ScrollRows(startAbsolute, height, -startAbsolute);
const auto end = _estimateOffsetOfLastCommittedRow();
for (auto y = height; y <= end; ++y)
{
GetMutableRowByOffset(y).Reset(_initialAttributes);
}
ScrollMarks(-start);
ClearMarksInRange(til::point{ 0, height }, til::point{ _width, _height });
}
// Routine Description:
// - This is the legacy screen resize with minimal changes
// Arguments:
@@ -1329,32 +1366,36 @@ til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, co
{
auto result = target;
const auto bufferSize = GetSize();
auto stayAtOrigin = false;
// ignore left boundary. Continue until readable text found
while (_GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
{
if (result == bufferSize.Origin())
if (!bufferSize.DecrementInBounds(result))
{
//looped around and hit origin (no word between origin and target)
return result;
// first char in buffer is a DelimiterChar or ControlChar
// we can't move any further back
stayAtOrigin = true;
break;
}
bufferSize.DecrementInBounds(result);
}
// make sure we expand to the left boundary or the beginning of the word
while (_GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
{
if (result == bufferSize.Origin())
if (!bufferSize.DecrementInBounds(result))
{
// first char in buffer is a RegularChar
// we can't move any further back
return result;
break;
}
bufferSize.DecrementInBounds(result);
}
// move off of delimiter
bufferSize.IncrementInBounds(result);
// move off of delimiter and onto word start
if (!stayAtOrigin && _GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
{
bufferSize.IncrementInBounds(result);
}
return result;
}
@@ -1372,16 +1413,10 @@ til::point TextBuffer::_GetWordStartForSelection(const til::point target, const
const auto bufferSize = GetSize();
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
// expand left until we hit the left boundary or a different delimiter class
while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
while (result.x > bufferSize.Left() && (_GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter))
{
//prevent selection wrapping on whitespace selection
if (isControlChar && result.x == bufferSize.Left())
{
break;
}
bufferSize.DecrementInBounds(result);
}
@@ -1459,21 +1494,25 @@ til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, cons
}
else
{
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
auto iter{ GetCellDataAt(result, bufferSize) };
while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) == DelimiterClass::RegularChar)
{
// Iterate through readable text
bufferSize.IncrementInBounds(result);
++iter;
}
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) != DelimiterClass::RegularChar)
{
// expand to the beginning of the NEXT word
bufferSize.IncrementInBounds(result);
++iter;
}
// Special case: we tried to move one past the end of the buffer
result = iter.Pos();
// Special case: we tried to move one past the end of the buffer,
// but iter prevented that (because that pos doesn't exist).
// Manually increment onto the EndExclusive point.
if (result == bufferSize.BottomRightInclusive())
if (!iter)
{
bufferSize.IncrementInBounds(result, true);
}
@@ -1493,18 +1532,19 @@ til::point TextBuffer::_GetWordEndForSelection(const til::point target, const st
{
const auto bufferSize = GetSize();
// can't expand right
if (target.x == bufferSize.RightInclusive())
{
return target;
}
auto result = target;
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
// expand right until we hit the right boundary as a ControlChar or a different delimiter class
while (result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
// expand right until we hit the right boundary or a different delimiter class
while (result.x < bufferSize.RightInclusive() && (_GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter))
{
if (isControlChar && result.x == bufferSize.RightInclusive())
{
break;
}
bufferSize.IncrementInBoundsCircular(result);
bufferSize.IncrementInBounds(result);
}
if (_GetDelimiterClassAt(result, wordDelimiters) != initialDelimiter)

View File

@@ -194,6 +194,7 @@ public:
til::point BufferToScreenPosition(const til::point position) const;
void Reset() noexcept;
void ClearScrollback(const til::CoordType start, const til::CoordType height);
void ResizeTraditional(const til::size newSize);

View File

@@ -38,9 +38,7 @@
</Properties>
<Dependencies>
<!-- rescap:appLicensing only works on 22000+. Until that's fixed, MinVersion will not let people install it on Windows 10... -->
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.22000.0" MaxVersionTested="10.0.22621.0" />
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.22000.0" MaxVersionTested="10.0.22621.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
</Dependencies>
<Resources>
@@ -94,7 +92,7 @@
Description="Console host built from microsoft/terminal open source repository"
PublicFolder="Public">
<uap3:Properties>
<Clsid>{A854D02A-F2FE-44A5-BB24-D03F4CF830D4}</Clsid>
<Clsid>{1F9F2BF5-5BC3-4F17-B0E6-912413F1F451}</Clsid>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
@@ -105,7 +103,7 @@
Description="Terminal host built from microsoft/terminal open source repository"
PublicFolder="Public">
<uap3:Properties>
<Clsid>{1706609C-A4CE-4C0D-B7D2-C19BF66398A5}</Clsid>
<Clsid>{051F34EE-C1FD-4B19-AF75-9BA54648434C}</Clsid>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>

View File

@@ -39,7 +39,6 @@
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
</Dependencies>
<Resources>

View File

@@ -40,7 +40,6 @@
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
</Dependencies>
<Resources>

View File

@@ -40,7 +40,6 @@
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
</Dependencies>
<Resources>

View File

@@ -68,6 +68,8 @@ Author(s):
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include <SafeDispatcherTimer.h>
// Common includes for most tests:
#include "../../inc/conattrs.hpp"
#include "../../types/inc/utils.hpp"

View File

@@ -1,6 +1,4 @@
#include "pch.h"
#include "ColorHelper.h"
#include <limits>
using namespace winrt::TerminalApp;

View File

@@ -1,7 +1,6 @@
#pragma once
#include "pch.h"
#include <winrt/windows.ui.core.h>
#include <winrt/Windows.UI.h>
namespace winrt::TerminalApp
{

View File

@@ -237,7 +237,9 @@
</ClCompile>
<ClCompile Include="Pane.cpp" />
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
<ClCompile Include="ColorHelper.cpp" />
<ClCompile Include="ColorHelper.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="DebugTapConnection.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>

View File

@@ -2631,6 +2631,75 @@ namespace winrt::TerminalApp::implementation
CATCH_LOG();
}
static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
{
bool success = false;
// OpenClipboard may fail to acquire the internal lock --> retry.
for (DWORD sleep = 10;; sleep *= 2)
{
if (OpenClipboard(hwnd))
{
success = true;
break;
}
// 10 iterations
if (sleep > 10000)
{
break;
}
Sleep(sleep);
}
return wil::unique_close_clipboard_call{ success };
}
static winrt::hstring _extractClipboard()
{
// This handles most cases of pasting text as the OS converts most formats to CF_UNICODETEXT automatically.
if (const auto handle = GetClipboardData(CF_UNICODETEXT))
{
const wil::unique_hglobal_locked lock{ handle };
const auto str = static_cast<const wchar_t*>(lock.get());
if (!str)
{
return {};
}
const auto maxLen = GlobalSize(handle) / sizeof(wchar_t);
const auto len = wcsnlen(str, maxLen);
return winrt::hstring{ str, gsl::narrow_cast<uint32_t>(len) };
}
// We get CF_HDROP when a user copied a file with Ctrl+C in Explorer and pastes that into the terminal (among others).
if (const auto handle = GetClipboardData(CF_HDROP))
{
const wil::unique_hglobal_locked lock{ handle };
const auto drop = static_cast<HDROP>(lock.get());
if (!drop)
{
return {};
}
const auto cap = DragQueryFileW(drop, 0, nullptr, 0);
if (cap == 0)
{
return {};
}
auto buffer = winrt::impl::hstring_builder{ cap };
const auto len = DragQueryFileW(drop, 0, buffer.data(), cap + 1);
if (len == 0)
{
return {};
}
return buffer.to_hstring();
}
return {};
}
// Function Description:
// - This function is called when the `TermControl` requests that we send
// it the clipboard's content.
@@ -2650,53 +2719,14 @@ namespace winrt::TerminalApp::implementation
const auto weakThis = get_weak();
const auto dispatcher = Dispatcher();
const auto globalSettings = _settings.GlobalSettings();
winrt::hstring text;
// GetClipboardData might block for up to 30s for delay-rendered contents.
co_await winrt::resume_background();
winrt::hstring text;
if (const auto clipboard = _openClipboard(nullptr))
{
// According to various reports on the internet, OpenClipboard might
// fail to acquire the internal lock, for instance due to rdpclip.exe.
for (int attempts = 1;;)
{
if (OpenClipboard(nullptr))
{
break;
}
if (attempts > 5)
{
co_return;
}
attempts++;
Sleep(10 * attempts);
}
const auto clipboardCleanup = wil::scope_exit([]() {
CloseClipboard();
});
const auto data = GetClipboardData(CF_UNICODETEXT);
if (!data)
{
co_return;
}
const auto str = static_cast<const wchar_t*>(GlobalLock(data));
if (!str)
{
co_return;
}
const auto dataCleanup = wil::scope_exit([&]() {
GlobalUnlock(data);
});
const auto maxLength = GlobalSize(data) / sizeof(wchar_t);
const auto length = wcsnlen(str, maxLength);
text = winrt::hstring{ str, gsl::narrow_cast<uint32_t>(length) };
text = _extractClipboard();
}
if (globalSettings.TrimPaste())

View File

@@ -121,12 +121,7 @@ namespace winrt::TerminalApp::implementation
void TerminalTab::_BellIndicatorTimerTick(const Windows::Foundation::IInspectable& /*sender*/, const Windows::Foundation::IInspectable& /*e*/)
{
ShowBellIndicator(false);
// Just do a sanity check that the timer still exists before we stop it
if (_bellIndicatorTimer.has_value())
{
_bellIndicatorTimer->Stop();
_bellIndicatorTimer = std::nullopt;
}
_bellIndicatorTimer.Stop();
}
// Method Description:
@@ -356,14 +351,13 @@ namespace winrt::TerminalApp::implementation
{
ASSERT_UI_THREAD();
if (!_bellIndicatorTimer.has_value())
if (!_bellIndicatorTimer)
{
DispatcherTimer bellIndicatorTimer;
bellIndicatorTimer.Interval(std::chrono::milliseconds(2000));
bellIndicatorTimer.Tick({ get_weak(), &TerminalTab::_BellIndicatorTimerTick });
bellIndicatorTimer.Start();
_bellIndicatorTimer.emplace(std::move(bellIndicatorTimer));
_bellIndicatorTimer.Interval(std::chrono::milliseconds(2000));
_bellIndicatorTimer.Tick({ get_weak(), &TerminalTab::_BellIndicatorTimerTick });
}
_bellIndicatorTimer.Start();
}
// Method Description:

View File

@@ -152,7 +152,7 @@ namespace winrt::TerminalApp::implementation
void _Setup();
std::optional<Windows::UI::Xaml::DispatcherTimer> _bellIndicatorTimer;
SafeDispatcherTimer _bellIndicatorTimer;
void _BellIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
void _MakeTabViewItem() override;

View File

@@ -783,10 +783,6 @@ namespace winrt::TerminalApp::implementation
{
_ShowLoadWarningsDialog(args.Warnings());
}
else if (args.Result() == S_OK)
{
DismissDialog();
}
_RefreshThemeRoutine();
}
}

View File

@@ -34,5 +34,5 @@ public:
private:
winrt::Microsoft::UI::Xaml::Controls::TeachingTip _tip;
winrt::Windows::UI::Xaml::DispatcherTimer _timer;
SafeDispatcherTimer _timer;
};

View File

@@ -83,6 +83,8 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include <SafeDispatcherTimer.h>
#include <cppwinrt_utils.h>
#include <wil/cppwinrt_helpers.h> // must go after the CoreDispatcher type is defined

View File

@@ -1652,7 +1652,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_searcher.ResetIfStale(*GetRenderData(), text, !goForward, !caseSensitive))
{
_searcher.HighlightResults();
_searcher.MoveToCurrentSelection();
_cachedSearchResultRows = {};
}
@@ -1669,6 +1668,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// DO NOT call _updateSelectionUI() here.
// We don't want to show the markers so manually tell it to clear it.
_terminal->SetBlockSelection(false);
_renderer->TriggerSelection();
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
foundResults->TotalMatches(gsl::narrow<int32_t>(_searcher.Results().size()));
@@ -1676,7 +1676,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->AlwaysNotifyOnBufferRotation(true);
}
_renderer->TriggerSelection();
// Raise a FoundMatch event, which the control will use to notify
// narrator if there was any results in the buffer

View File

@@ -57,10 +57,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_isInternalScrollBarUpdate{ false },
_autoScrollVelocity{ 0 },
_autoScrollingPointerPoint{ std::nullopt },
_autoScrollTimer{},
_lastAutoScrollUpdateTime{ std::nullopt },
_cursorTimer{},
_blinkTimer{},
_searchBox{ nullptr }
{
InitializeComponent();
@@ -1087,10 +1084,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (blinkTime != INFINITE)
{
// Create a timer
DispatcherTimer cursorTimer;
cursorTimer.Interval(std::chrono::milliseconds(blinkTime));
cursorTimer.Tick({ get_weak(), &TermControl::_CursorTimerTick });
_cursorTimer.emplace(std::move(cursorTimer));
_cursorTimer.Interval(std::chrono::milliseconds(blinkTime));
_cursorTimer.Tick({ get_weak(), &TermControl::_CursorTimerTick });
// As of GH#6586, don't start the cursor timer immediately, and
// don't show the cursor initially. We'll show the cursor and start
// the timer when the control is first focused.
@@ -1105,13 +1100,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core.CursorOn(_focused || _displayCursorWhileBlurred());
if (_displayCursorWhileBlurred())
{
_cursorTimer->Start();
_cursorTimer.Start();
}
}
else
{
// The user has disabled cursor blinking
_cursorTimer = std::nullopt;
_cursorTimer.Destroy();
}
// Set up blinking attributes
@@ -1120,16 +1114,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (animationsEnabled && blinkTime != INFINITE)
{
// Create a timer
DispatcherTimer blinkTimer;
blinkTimer.Interval(std::chrono::milliseconds(blinkTime));
blinkTimer.Tick({ get_weak(), &TermControl::_BlinkTimerTick });
blinkTimer.Start();
_blinkTimer.emplace(std::move(blinkTimer));
_blinkTimer.Interval(std::chrono::milliseconds(blinkTime));
_blinkTimer.Tick({ get_weak(), &TermControl::_BlinkTimerTick });
_blinkTimer.Start();
}
else
{
// The user has disabled blinking
_blinkTimer = std::nullopt;
_blinkTimer.Destroy();
}
// Now that the renderer is set up, update the appearance for initialization
@@ -1498,7 +1490,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Manually show the cursor when a key is pressed. Restarting
// the timer prevents flickering.
_core.CursorOn(_core.SelectionMode() != SelectionInteractionMode::Mark);
_cursorTimer->Start();
_cursorTimer.Start();
}
return handled;
@@ -1973,12 +1965,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// When the terminal focuses, show the cursor immediately
_core.CursorOn(_core.SelectionMode() != SelectionInteractionMode::Mark);
_cursorTimer->Start();
_cursorTimer.Start();
}
if (_blinkTimer)
{
_blinkTimer->Start();
_blinkTimer.Start();
}
// Only update the appearance here if an unfocused config exists - if an
@@ -2021,13 +2013,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_cursorTimer && !_displayCursorWhileBlurred())
{
_cursorTimer->Stop();
_cursorTimer.Stop();
_core.CursorOn(false);
}
if (_blinkTimer)
{
_blinkTimer->Stop();
_blinkTimer.Stop();
}
// Check if there is an unfocused config we should set the appearance to
@@ -2278,7 +2270,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Disconnect the TSF input control so it doesn't receive EditContext events.
TSFInputControl().Close();
// At the time of writing, closing the last tab of a window inexplicably
// does not lead to the destruction of the remaining TermControl instance(s).
// On Win10 we don't destroy window threads due to bugs in DesktopWindowXamlSource.
// In turn, we leak TermControl instances. This results in constant HWND messages
// while the thread is supposed to be idle. Stop these timers avoids this.
_autoScrollTimer.Stop();
_bellLightTimer.Stop();
_cursorTimer.Stop();
_blinkTimer.Stop();
if (!_detached)
{
@@ -2908,9 +2909,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// However, it's likely that the control layer may need to
// know about the source anyways in the future, to support
// GH#3158
const auto isWSL = _interactivity.ManglePathsForWsl();
if (isWSL)
if (_interactivity.ManglePathsForWsl())
{
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
@@ -2944,19 +2943,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
const auto quotesNeeded = isWSL || fullPath.find(L' ') != std::wstring::npos;
const auto quotesChar = isWSL ? L'\'' : L'"';
const auto containsSpaces = std::find(fullPath.begin(),
fullPath.end(),
L' ') != fullPath.end();
// Append fullPath and also wrap it in quotes if needed
if (quotesNeeded)
if (containsSpaces)
{
allPathsString.push_back(quotesChar);
}
allPathsString.append(fullPath);
if (quotesNeeded)
{
allPathsString.push_back(quotesChar);
fullPath.insert(0, L"\"");
fullPath += L"\"";
}
allPathsString += fullPath;
}
_pasteTextWithBroadcast(winrt::hstring{ allPathsString });
@@ -3129,20 +3126,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_bellDarkAnimation.Duration(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(TerminalWarningBellInterval)));
}
// Similar to the animation, only initialize the timer here
if (!_bellLightTimer)
{
_bellLightTimer = {};
_bellLightTimer.Interval(std::chrono::milliseconds(TerminalWarningBellInterval));
_bellLightTimer.Tick({ get_weak(), &TermControl::_BellLightOff });
}
Windows::Foundation::Numerics::float2 zeroSize{ 0, 0 };
// If the grid has 0 size or if the bell timer is
// already active, do nothing
if (RootGrid().ActualSize() != zeroSize && !_bellLightTimer.IsEnabled())
{
// Start the timer, when the timer ticks we switch off the light
_bellLightTimer.Interval(std::chrono::milliseconds(TerminalWarningBellInterval));
_bellLightTimer.Tick({ get_weak(), &TermControl::_BellLightOff });
_bellLightTimer.Start();
// Switch on the light and animate the intensity to fade out
@@ -3162,15 +3152,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TermControl::_BellLightOff(const Windows::Foundation::IInspectable& /* sender */,
const Windows::Foundation::IInspectable& /* e */)
{
if (_bellLightTimer)
{
// Stop the timer and switch off the light
_bellLightTimer.Stop();
// Stop the timer and switch off the light
_bellLightTimer.Stop();
if (!_IsClosing())
{
VisualBellLight::SetIsTarget(RootGrid(), false);
}
if (!_IsClosing())
{
VisualBellLight::SetIsTarget(RootGrid(), false);
}
}
@@ -3729,9 +3716,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// If we should be ALWAYS displaying the cursor, turn it on and start blinking.
_core.CursorOn(true);
if (_cursorTimer.has_value())
if (_cursorTimer)
{
_cursorTimer->Start();
_cursorTimer.Start();
}
}
else
@@ -3740,9 +3727,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// blinking. (if we're focused, then we're already doing the right
// thing)
const auto focused = FocusState() != FocusState::Unfocused;
if (!focused && _cursorTimer.has_value())
if (!focused && _cursorTimer)
{
_cursorTimer->Stop();
_cursorTimer.Stop();
}
_core.CursorOn(focused);
}

View File

@@ -236,16 +236,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// viewport. View is then scrolled to 'follow' the cursor.
double _autoScrollVelocity;
std::optional<Windows::UI::Input::PointerPoint> _autoScrollingPointerPoint;
Windows::UI::Xaml::DispatcherTimer _autoScrollTimer;
SafeDispatcherTimer _autoScrollTimer;
std::optional<std::chrono::high_resolution_clock::time_point> _lastAutoScrollUpdateTime;
bool _pointerPressedInBounds{ false };
winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellLightAnimation{ nullptr };
winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellDarkAnimation{ nullptr };
Windows::UI::Xaml::DispatcherTimer _bellLightTimer{ nullptr };
SafeDispatcherTimer _bellLightTimer;
std::optional<Windows::UI::Xaml::DispatcherTimer> _cursorTimer;
std::optional<Windows::UI::Xaml::DispatcherTimer> _blinkTimer;
SafeDispatcherTimer _cursorTimer;
SafeDispatcherTimer _blinkTimer;
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
bool _showMarksInScrollbar{ false };

View File

@@ -92,8 +92,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const
{
// Call the function off of the underlying UiaTextRange.
VARIANT result;
THROW_IF_FAILED(_uiaProvider->GetAttributeValue(textAttributeId, &result));
wil::unique_variant result;
THROW_IF_FAILED(_uiaProvider->GetAttributeValue(textAttributeId, result.addressof()));
// Convert the resulting VARIANT into a format that is consumable by XAML.
switch (result.vt)
@@ -189,9 +189,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::hstring XamlUiaTextRange::GetText(int32_t maxLength) const
{
BSTR returnVal;
THROW_IF_FAILED(_uiaProvider->GetText(maxLength, &returnVal));
return winrt::to_hstring(returnVal);
wil::unique_bstr returnVal;
THROW_IF_FAILED(_uiaProvider->GetText(maxLength, returnVal.put()));
return winrt::hstring{ returnVal.get(), SysStringLen(returnVal.get()) };
}
int32_t XamlUiaTextRange::Move(XamlAutomation::TextUnit unit,

View File

@@ -73,7 +73,8 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalControlProvider);
#include <til/mutex.h>
#include <til/winrt.h>
#include "ThrottledFunc.h"
#include <SafeDispatcherTimer.h>
#include <ThrottledFunc.h>
#include <cppwinrt_utils.h>
#include <wil/cppwinrt_helpers.h> // must go after the CoreDispatcher type is defined

View File

@@ -215,12 +215,10 @@ public:
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept override;
std::vector<Microsoft::Console::Types::Viewport> GetSelectionRects() noexcept override;
std::vector<Microsoft::Console::Types::Viewport> GetSearchSelectionRects() noexcept override;
const bool IsSelectionActive() const noexcept override;
const bool IsBlockSelection() const noexcept override;
void ClearSelection() override;
void SelectNewRegion(const til::point coordStart, const til::point coordEnd) override;
void SelectSearchRegions(std::vector<til::inclusive_rect> source) override;
const til::point GetSelectionAnchor() const noexcept override;
const til::point GetSelectionEnd() const noexcept override;
const std::wstring_view GetConsoleTitle() const noexcept override;
@@ -379,7 +377,6 @@ private:
til::point pivot;
};
std::optional<SelectionAnchors> _selection;
std::vector<til::inclusive_rect> _searchSelections;
bool _blockSelection = false;
std::wstring _wordDelimiters;
SelectionExpansion _multiClickSelectionMode = SelectionExpansion::Char;
@@ -467,7 +464,6 @@ private:
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
std::vector<til::inclusive_rect> _GetSelectionRects() const noexcept;
std::vector<til::inclusive_rect> _GetSearchSelectionRects(Microsoft::Console::Types::Viewport viewport) const noexcept;
std::vector<til::point_span> _GetSelectionSpans() const noexcept;
std::pair<til::point, til::point> _PivotSelection(const til::point targetPos, bool& targetStart) const noexcept;
std::pair<til::point, til::point> _ExpandSelectionAnchors(std::pair<til::point, til::point> anchors) const;

View File

@@ -63,40 +63,6 @@ std::vector<til::inclusive_rect> Terminal::_GetSelectionRects() const noexcept
return result;
}
// Method Description:
// - Helper to determine the selected region of the buffer. Used for rendering.
// Return Value:
// - A vector of rectangles representing the regions to select, line by line. They are absolute coordinates relative to the buffer origin.
std::vector<til::inclusive_rect> Terminal::_GetSearchSelectionRects(Microsoft::Console::Types::Viewport viewport) const noexcept
{
std::vector<til::inclusive_rect> result;
try
{
auto lowerIt = std::lower_bound(_searchSelections.begin(), _searchSelections.end(), viewport.Top(), [](const til::inclusive_rect& rect, til::CoordType value) {
return rect.top < value;
});
auto upperIt = std::upper_bound(_searchSelections.begin(), _searchSelections.end(), viewport.BottomExclusive(), [](til::CoordType value, const til::inclusive_rect& rect) {
return value < rect.top;
});
for (auto selection = lowerIt; selection != upperIt; ++selection)
{
const auto start = til::point{ selection->left, selection->top };
const auto end = til::point{ selection->right, selection->top };
const auto adj = _activeBuffer().GetTextRects(start, end, _blockSelection, false);
for (auto a : adj)
{
result.emplace_back(a);
}
}
return result;
}
CATCH_LOG();
return result;
}
// Method Description:
// - Identical to GetTextRects if it's a block selection, else returns a single span for the whole selection.
// Return Value:
@@ -858,7 +824,6 @@ void Terminal::_MoveByBuffer(SelectionDirection direction, til::point& pos) noex
void Terminal::ClearSelection()
{
_assertLocked();
_searchSelections.clear();
_selection = std::nullopt;
_selectionMode = SelectionInteractionMode::None;
_selectionIsTargetingUrl = false;

View File

@@ -150,24 +150,6 @@ catch (...)
return {};
}
std::vector<Microsoft::Console::Types::Viewport> Terminal::GetSearchSelectionRects() noexcept
try
{
std::vector<Viewport> result;
for (const auto& lineRect : _GetSearchSelectionRects(_GetVisibleViewport()))
{
result.emplace_back(Viewport::FromInclusive(lineRect));
}
return result;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return {};
}
void Terminal::SelectNewRegion(const til::point coordStart, const til::point coordEnd)
{
#pragma warning(push)
@@ -206,23 +188,6 @@ void Terminal::SelectNewRegion(const til::point coordStart, const til::point coo
SetSelectionEnd(realCoordEnd, SelectionExpansion::Char);
}
void Terminal::SelectSearchRegions(std::vector<til::inclusive_rect> rects)
{
_searchSelections.clear();
for (auto& rect : rects)
{
rect.top -= _VisibleStartIndex();
rect.bottom -= _VisibleStartIndex();
const auto realStart = _ConvertToBufferCell(til::point{ rect.left, rect.top });
const auto realEnd = _ConvertToBufferCell(til::point{ rect.right, rect.bottom });
auto rr = til::inclusive_rect{ realStart.x, realStart.y, realEnd.x, realEnd.y };
_searchSelections.emplace_back(rr);
}
}
const std::wstring_view Terminal::GetConsoleTitle() const noexcept
{
_assertLocked();

View File

@@ -326,29 +326,31 @@
</ResourceDictionary>
</Page.Resources>
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<StackPanel MaxWidth="600"
HorizontalAlignment="Left"
Spacing="8"
Style="{StaticResource SettingsStackStyle}">
<!-- Add New Button -->
<Button x:Name="AddNewButton"
Click="AddNew_Click">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="Actions_AddNewTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
<ScrollViewer ViewChanging="ViewChanging">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<StackPanel MaxWidth="600"
HorizontalAlignment="Left"
Spacing="8"
Style="{StaticResource SettingsStackStyle}">
<!-- Add New Button -->
<Button x:Name="AddNewButton"
Click="AddNew_Click">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="Actions_AddNewTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
<!-- Keybindings -->
<ListView x:Name="KeyBindingsListView"
ItemTemplate="{StaticResource KeyBindingTemplate}"
ItemsSource="{x:Bind KeyBindingList, Mode=OneWay}"
SelectionMode="None" />
</StackPanel>
</Border>
<!-- Keybindings -->
<ListView x:Name="KeyBindingsListView"
ItemTemplate="{StaticResource KeyBindingTemplate}"
ItemsSource="{x:Bind KeyBindingList, Mode=OneWay}"
SelectionMode="None" />
</StackPanel>
</Border>
</ScrollViewer>
</Page>

View File

@@ -21,70 +21,72 @@
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Button x:Name="AddNewButton"
Click="AddNewClick"
Style="{StaticResource AccentButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="AddProfile_AddNewTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
</Border>
<StackPanel Margin="{StaticResource StandardControlMargin}">
<local:SettingContainer x:Uid="AddProfile_Duplicate">
<ComboBox x:Name="Profiles"
AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind State.Settings.AllProfiles, Mode=OneWay}"
SelectedIndex="0"
SelectionChanged="ProfilesSelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind Icon, Converter={StaticResource IconSourceConverter}}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Button x:Name="DuplicateButton"
Margin="{StaticResource StandardControlMargin}"
Click="DuplicateClick"
IsEnabled="{x:Bind IsProfileSelected, Mode=OneWay}"
<Button x:Name="AddNewButton"
Click="AddNewClick"
Style="{StaticResource AccentButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8C8;" />
<TextBlock x:Uid="AddProfile_DuplicateTextBlock"
Glyph="&#xE710;" />
<TextBlock x:Uid="AddProfile_AddNewTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
</Border>
<StackPanel Margin="{StaticResource StandardControlMargin}">
<local:SettingContainer x:Uid="AddProfile_Duplicate">
<ComboBox x:Name="Profiles"
AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind State.Settings.AllProfiles, Mode=OneWay}"
SelectedIndex="0"
SelectionChanged="ProfilesSelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind Icon, Converter={StaticResource IconSourceConverter}}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Button x:Name="DuplicateButton"
Margin="{StaticResource StandardControlMargin}"
Click="DuplicateClick"
IsEnabled="{x:Bind IsProfileSelected, Mode=OneWay}"
Style="{StaticResource AccentButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8C8;" />
<TextBlock x:Uid="AddProfile_DuplicateTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
</Border>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -115,6 +115,7 @@
<!-- Used for disclaimers -->
<Style x:Key="DisclaimerStyle"
TargetType="TextBlock">
<Setter Property="FontStyle" Value="Italic" />
<Setter Property="TextWrapping" Value="WrapWholeWords" />
<Setter Property="MaxWidth" Value="1000" />
</Style>

View File

@@ -82,419 +82,421 @@
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<!-- Preview of the selected scheme -->
<Grid Width="350"
Height="160"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="4"
HorizontalAlignment="Left"
Background="{x:Bind local:Converters.ColorToBrush(ViewModel.BackgroundColor.Color), Mode=OneWay}"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0"
Grid.Column="0"
Content="{x:Bind ViewModel.ForegroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="1"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(0), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="2"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(1), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="3"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(2), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="4"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(3), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="5"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(4), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="6"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(5), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="7"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(6), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="8"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(7), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="1"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(8), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="2"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(9), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="3"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(10), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="4"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(11), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="5"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(12), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="6"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(13), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="7"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(14), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="8"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(15), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<!-- Preview of the selected scheme -->
<Grid Width="350"
Height="160"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="4"
HorizontalAlignment="Left"
Background="{x:Bind local:Converters.ColorToBrush(ViewModel.BackgroundColor.Color), Mode=OneWay}"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0"
Grid.Column="0"
Content="{x:Bind ViewModel.ForegroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="1"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(0), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="2"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(1), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="3"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(2), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="4"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(3), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="5"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(4), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="6"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(5), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="7"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(6), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="8"
Grid.Column="0"
Content="{x:Bind ViewModel.ColorEntryAt(7), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="1"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(8), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="2"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(9), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="3"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(10), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="4"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(11), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="5"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(12), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="6"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(13), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="7"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(14), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
<ContentControl Grid.Row="8"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(15), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableTextBlockTemplate}"
IsTabStop="False" />
</Grid>
</Border>
</Grid>
</Border>
<local:SettingContainer x:Uid="ColorScheme_ColorsHeader"
StartExpanded="True"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid x:Name="ColorTableGrid"
Style="{StaticResource ColorTableGridStyle}"
XYFocusKeyboardNavigation="Enabled">
<Grid.ColumnDefinitions>
<!-- Labels -->
<ColumnDefinition Width="Auto" />
<local:SettingContainer x:Uid="ColorScheme_ColorsHeader"
StartExpanded="True"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid x:Name="ColorTableGrid"
Style="{StaticResource ColorTableGridStyle}"
XYFocusKeyboardNavigation="Enabled">
<Grid.ColumnDefinitions>
<!-- Labels -->
<ColumnDefinition Width="Auto" />
<!-- Regular Colors -->
<ColumnDefinition Width="Auto" />
<!-- Regular Colors -->
<ColumnDefinition Width="Auto" />
<!-- Bright Colors -->
<ColumnDefinition Width="Auto" />
<!-- Bright Colors -->
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<!-- Labels -->
<ColumnDefinition Width="Auto" />
<!-- Labels -->
<ColumnDefinition Width="Auto" />
<!-- Regular Colors -->
<ColumnDefinition Width="Auto" />
<!-- Regular Colors -->
<ColumnDefinition Width="Auto" />
<!-- Bright Colors -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Bright Colors -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Uid="ColorScheme_Black"
Grid.Row="0"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightBlack"
Grid.Row="0"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(0), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Red"
Grid.Row="1"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightRed"
Grid.Row="1"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(1), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Green"
Grid.Row="2"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightGreen"
Grid.Row="2"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(2), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Yellow"
Grid.Row="3"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightYellow"
Grid.Row="3"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(3), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Blue"
Grid.Row="4"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightBlue"
Grid.Row="4"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(4), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Purple"
Grid.Row="5"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightPurple"
Grid.Row="5"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(5), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Cyan"
Grid.Row="6"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightCyan"
Grid.Row="6"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(6), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_White"
Grid.Row="7"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightWhite"
Grid.Row="7"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(7), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightBlack"
Grid.Row="0"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(8), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightRed"
Grid.Row="1"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(9), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightGreen"
Grid.Row="2"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(10), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightYellow"
Grid.Row="3"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(11), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightBlue"
Grid.Row="4"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(12), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightPurple"
Grid.Row="5"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(13), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightCyan"
Grid.Row="6"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(14), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightWhite"
Grid.Row="7"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(15), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Uid="ColorScheme_Black"
Grid.Row="0"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightBlack"
Grid.Row="0"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(0), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Red"
Grid.Row="1"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightRed"
Grid.Row="1"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(1), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Green"
Grid.Row="2"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightGreen"
Grid.Row="2"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(2), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Yellow"
Grid.Row="3"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightYellow"
Grid.Row="3"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(3), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Blue"
Grid.Row="4"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightBlue"
Grid.Row="4"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(4), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Purple"
Grid.Row="5"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightPurple"
Grid.Row="5"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(5), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_Cyan"
Grid.Row="6"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightCyan"
Grid.Row="6"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(6), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<TextBlock x:Uid="ColorScheme_White"
Grid.Row="7"
Grid.Column="0"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="NonBrightWhite"
Grid.Row="7"
Grid.Column="1"
Content="{x:Bind ViewModel.ColorEntryAt(7), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightBlack"
Grid.Row="0"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(8), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightRed"
Grid.Row="1"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(9), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightGreen"
Grid.Row="2"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(10), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightYellow"
Grid.Row="3"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(11), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightBlue"
Grid.Row="4"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(12), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightPurple"
Grid.Row="5"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(13), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightCyan"
Grid.Row="6"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(14), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<ContentControl x:Name="BrightWhite"
Grid.Row="7"
Grid.Column="2"
Content="{x:Bind ViewModel.ColorEntryAt(15), Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Foreground -->
<TextBlock x:Uid="ColorScheme_Foreground"
Grid.Row="0"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="ForegroundButton"
Grid.Row="0"
Grid.Column="5"
Content="{x:Bind ViewModel.ForegroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Foreground -->
<TextBlock x:Uid="ColorScheme_Foreground"
Grid.Row="0"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="ForegroundButton"
Grid.Row="0"
Grid.Column="5"
Content="{x:Bind ViewModel.ForegroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Background -->
<TextBlock x:Uid="ColorScheme_Background"
Grid.Row="1"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="BackgroundButton"
Grid.Row="1"
Grid.Column="5"
Content="{x:Bind ViewModel.BackgroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Background -->
<TextBlock x:Uid="ColorScheme_Background"
Grid.Row="1"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="BackgroundButton"
Grid.Row="1"
Grid.Column="5"
Content="{x:Bind ViewModel.BackgroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Cursor Color -->
<TextBlock x:Uid="ColorScheme_CursorColor"
Grid.Row="2"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="CursorColorButton"
Grid.Row="2"
Grid.Column="5"
Content="{x:Bind ViewModel.CursorColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Cursor Color -->
<TextBlock x:Uid="ColorScheme_CursorColor"
Grid.Row="2"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="CursorColorButton"
Grid.Row="2"
Grid.Column="5"
Content="{x:Bind ViewModel.CursorColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
<!-- Selection Background -->
<TextBlock x:Uid="ColorScheme_SelectionBackground"
Grid.Row="3"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="SelectionBackgroundButton"
Grid.Row="3"
Grid.Column="5"
Content="{x:Bind ViewModel.SelectionBackgroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
</Grid>
</local:SettingContainer>
<!-- Selection Background -->
<TextBlock x:Uid="ColorScheme_SelectionBackground"
Grid.Row="3"
Grid.Column="4"
Style="{StaticResource ColorLabelStyle}" />
<ContentControl x:Name="SelectionBackgroundButton"
Grid.Row="3"
Grid.Column="5"
Content="{x:Bind ViewModel.SelectionBackgroundColor, Mode=OneWay}"
ContentTemplate="{StaticResource ColorTableEntryTemplate}"
Style="{StaticResource ColorControlStyle}" />
</Grid>
</local:SettingContainer>
<local:SettingContainer x:Name="SetAsDefaultContainer"
x:Uid="ColorScheme_SetAsDefault">
<Button x:Name="SetAsDefaultButton"
x:Uid="ColorScheme_SetAsDefaultButton"
Click="{x:Bind ViewModel.SetAsDefault_Click}"
Style="{StaticResource BrowseButtonStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Name="SetAsDefaultContainer"
x:Uid="ColorScheme_SetAsDefault">
<Button x:Name="SetAsDefaultButton"
x:Uid="ColorScheme_SetAsDefaultButton"
Click="{x:Bind ViewModel.SetAsDefault_Click}"
Style="{StaticResource BrowseButtonStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Name="RenameContainer"
x:Uid="ColorScheme_Rename"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.IsInBoxScheme), Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Horizontal"
XYFocusKeyboardNavigation="Enabled">
<!-- Shown when color scheme name is already in use -->
<muxc:TeachingTip x:Name="RenameErrorTip"
x:Uid="ColorScheme_RenameErrorTip" />
<!-- Name text box -->
<TextBox x:Name="NameBox"
PreviewKeyDown="NameBox_PreviewKeyDown"
Style="{StaticResource TextBoxSettingStyle}" />
<!-- Accept rename button -->
<Button x:Name="RenameAcceptButton"
x:Uid="RenameAccept"
Click="RenameAccept_Click"
Style="{StaticResource AccentSmallButtonStyle}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8FB;" />
</StackPanel>
</Button>
<!-- Cancel rename button -->
<Button x:Name="RenameCancelButton"
x:Uid="RenameCancel"
Click="RenameCancel_Click"
Style="{StaticResource SmallButtonStyle}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE711;" />
</StackPanel>
</Button>
</StackPanel>
</local:SettingContainer>
<Grid MaxWidth="1000"
Margin="2,6,0,0"
ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="DeleteButton"
Grid.Column="0"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.IsInBoxScheme)}"
Style="{StaticResource DeleteButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="ColorScheme_DeleteButton"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="ColorScheme_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="ColorScheme_DeleteConfirmationButton"
Click="{x:Bind ViewModel.DeleteConfirmation_Click}" />
<local:SettingContainer x:Name="RenameContainer"
x:Uid="ColorScheme_Rename"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.IsInBoxScheme), Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Horizontal"
XYFocusKeyboardNavigation="Enabled">
<!-- Shown when color scheme name is already in use -->
<muxc:TeachingTip x:Name="RenameErrorTip"
x:Uid="ColorScheme_RenameErrorTip" />
<!-- Name text box -->
<TextBox x:Name="NameBox"
PreviewKeyDown="NameBox_PreviewKeyDown"
Style="{StaticResource TextBoxSettingStyle}" />
<!-- Accept rename button -->
<Button x:Name="RenameAcceptButton"
x:Uid="RenameAccept"
Click="RenameAccept_Click"
Style="{StaticResource AccentSmallButtonStyle}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8FB;" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<TextBlock x:Name="SelectedSchemeDisclaimer"
x:Uid="ColorScheme_DeleteButtonDisclaimerInBox"
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource DisclaimerStyle}"
TextWrapping="Wrap"
Visibility="{x:Bind ViewModel.IsInBoxScheme}" />
</Grid>
</StackPanel>
</Button>
<!-- Cancel rename button -->
<Button x:Name="RenameCancelButton"
x:Uid="RenameCancel"
Click="RenameCancel_Click"
Style="{StaticResource SmallButtonStyle}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE711;" />
</StackPanel>
</Button>
</StackPanel>
</local:SettingContainer>
<Grid MaxWidth="1000"
Margin="2,6,0,0"
ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="DeleteButton"
Grid.Column="0"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.IsInBoxScheme)}"
Style="{StaticResource DeleteButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="ColorScheme_DeleteButton"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="ColorScheme_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="ColorScheme_DeleteConfirmationButton"
Click="{x:Bind ViewModel.DeleteConfirmation_Click}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<TextBlock x:Name="SelectedSchemeDisclaimer"
x:Uid="ColorScheme_DeleteButtonDisclaimerInBox"
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource DisclaimerStyle}"
TextWrapping="Wrap"
Visibility="{x:Bind ViewModel.IsInBoxScheme}" />
</Grid>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -25,107 +25,109 @@
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Language -->
<local:SettingContainer x:Uid="Globals_Language"
Visibility="{x:Bind ViewModel.LanguageSelectorAvailable}">
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.LanguageDisplayConverter((x:String))}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Language -->
<local:SettingContainer x:Uid="Globals_Language"
Visibility="{x:Bind ViewModel.LanguageSelectorAvailable}">
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.LanguageDisplayConverter((x:String))}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Theme -->
<local:SettingContainer x:Uid="Globals_Theme">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind ViewModel.ThemeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Theme">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.ThemeNameConverter((model:Theme)), Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Theme -->
<local:SettingContainer x:Uid="Globals_Theme">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind ViewModel.ThemeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Theme">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.ThemeNameConverter((model:Theme)), Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Position of new tab -->
<local:SettingContainer x:Uid="Globals_NewTabPosition">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.NewTabPositionList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentNewTabPosition, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Position of new tab -->
<local:SettingContainer x:Uid="Globals_NewTabPosition">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.NewTabPositionList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentNewTabPosition, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Show Titlebar -->
<local:SettingContainer x:Uid="Globals_ShowTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}"
Toggled="{x:Bind ViewModel.ShowTitlebarToggled}" />
</local:SettingContainer>
<!-- Show Titlebar -->
<local:SettingContainer x:Uid="Globals_ShowTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}"
Toggled="{x:Bind ViewModel.ShowTitlebarToggled}" />
</local:SettingContainer>
<!-- Always show tabs -->
<local:SettingContainer x:Uid="Globals_AlwaysShowTabs">
<ToggleSwitch IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.ShowTabsInTitlebar), Mode=OneWay}"
IsOn="{x:Bind ViewModel.AlwaysShowTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always show tabs -->
<local:SettingContainer x:Uid="Globals_AlwaysShowTabs">
<ToggleSwitch IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.ShowTabsInTitlebar), Mode=OneWay}"
IsOn="{x:Bind ViewModel.AlwaysShowTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Acrylic in Tab Row -->
<local:SettingContainer x:Uid="Globals_AcrylicTabRow">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAcrylicInTabRow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Acrylic in Tab Row -->
<local:SettingContainer x:Uid="Globals_AcrylicTabRow">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAcrylicInTabRow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Title in Titlebar -->
<local:SettingContainer x:Uid="Globals_ShowTitleInTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTitleInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Title in Titlebar -->
<local:SettingContainer x:Uid="Globals_ShowTitleInTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTitleInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always on Top -->
<local:SettingContainer x:Uid="Globals_AlwaysOnTop">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysOnTop, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always on Top -->
<local:SettingContainer x:Uid="Globals_AlwaysOnTop">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysOnTop, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Tab Width Mode -->
<local:SettingContainer x:Uid="Globals_TabWidthMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabWidthModeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTabWidthMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Tab Width Mode -->
<local:SettingContainer x:Uid="Globals_TabWidthMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabWidthModeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTabWidthMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Disable Animations -->
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
<local:SettingContainer x:Uid="Globals_DisableAnimationsReversed">
<ToggleSwitch IsOn="{x:Bind ViewModel.InvertedDisableAnimations, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Disable Animations -->
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
<local:SettingContainer x:Uid="Globals_DisableAnimationsReversed">
<ToggleSwitch IsOn="{x:Bind ViewModel.InvertedDisableAnimations, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always Show Notification Icon -->
<local:SettingContainer x:Uid="Globals_AlwaysShowNotificationIcon">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowNotificationIcon, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always Show Notification Icon -->
<local:SettingContainer x:Uid="Globals_AlwaysShowNotificationIcon">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowNotificationIcon, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Minimize To Notification Area -->
<local:SettingContainer x:Uid="Globals_MinimizeToNotificationArea">
<ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Minimize To Notification Area -->
<local:SettingContainer x:Uid="Globals_MinimizeToNotificationArea">
<ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Automatically hide window -->
<local:SettingContainer x:Uid="Globals_AutoHideWindow">
<ToggleSwitch IsOn="{x:Bind ViewModel.AutoHideWindow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Automatically hide window -->
<local:SettingContainer x:Uid="Globals_AutoHideWindow">
<ToggleSwitch IsOn="{x:Bind ViewModel.AutoHideWindow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -24,73 +24,75 @@
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Copy On Select -->
<local:SettingContainer x:Uid="Globals_CopyOnSelect">
<ToggleSwitch IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Copy On Select -->
<local:SettingContainer x:Uid="Globals_CopyOnSelect">
<ToggleSwitch IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Copy Format -->
<local:SettingContainer x:Uid="Globals_CopyFormat">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.CopyFormatList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentCopyFormat, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Copy Format -->
<local:SettingContainer x:Uid="Globals_CopyFormat">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.CopyFormatList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentCopyFormat, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Trim Block Selection -->
<local:SettingContainer x:Uid="Globals_TrimBlockSelection">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimBlockSelection, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Trim Block Selection -->
<local:SettingContainer x:Uid="Globals_TrimBlockSelection">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimBlockSelection, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Trim Paste -->
<local:SettingContainer x:Uid="Globals_TrimPaste">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimPaste, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Trim Paste -->
<local:SettingContainer x:Uid="Globals_TrimPaste">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimPaste, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Word Delimiters -->
<local:SettingContainer x:Uid="Globals_WordDelimiters"
CurrentValue="{x:Bind ViewModel.WordDelimiters, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.WordDelimiters, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Word Delimiters -->
<local:SettingContainer x:Uid="Globals_WordDelimiters"
CurrentValue="{x:Bind ViewModel.WordDelimiters, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.WordDelimiters, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Snap On Resize -->
<local:SettingContainer x:Uid="Globals_SnapToGridOnResize">
<ToggleSwitch IsOn="{x:Bind ViewModel.SnapToGridOnResize, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Snap On Resize -->
<local:SettingContainer x:Uid="Globals_SnapToGridOnResize">
<ToggleSwitch IsOn="{x:Bind ViewModel.SnapToGridOnResize, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Tab Switcher Mode -->
<local:SettingContainer x:Uid="Globals_TabSwitcherMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabSwitcherModeList}"
SelectedItem="{x:Bind ViewModel.CurrentTabSwitcherMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Tab Switcher Mode -->
<local:SettingContainer x:Uid="Globals_TabSwitcherMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabSwitcherModeList}"
SelectedItem="{x:Bind ViewModel.CurrentTabSwitcherMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Focus Follow Mouse Mode -->
<local:SettingContainer x:Uid="Globals_FocusFollowMouse">
<ToggleSwitch IsOn="{x:Bind ViewModel.FocusFollowMouse, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Focus Follow Mouse Mode -->
<local:SettingContainer x:Uid="Globals_FocusFollowMouse">
<ToggleSwitch IsOn="{x:Bind ViewModel.FocusFollowMouse, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Detect URLs -->
<local:SettingContainer x:Uid="Globals_DetectURLs">
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Detect URLs -->
<local:SettingContainer x:Uid="Globals_DetectURLs">
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Uid="Globals_ConfirmCloseAllTabs">
<ToggleSwitch IsOn="{x:Bind ViewModel.ConfirmCloseAllTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<local:SettingContainer x:Uid="Globals_ConfirmCloseAllTabs">
<ToggleSwitch IsOn="{x:Bind ViewModel.ConfirmCloseAllTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -41,242 +41,244 @@
</ResourceDictionary>
</Page.Resources>
<StackPanel>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Default Profile -->
<local:SettingContainer x:Uid="Globals_DefaultProfile">
<ComboBox x:Name="DefaultProfile"
ItemsSource="{x:Bind ViewModel.DefaultProfiles}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultProfile, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Default Profile -->
<local:SettingContainer x:Uid="Globals_DefaultProfile">
<ComboBox x:Name="DefaultProfile"
ItemsSource="{x:Bind ViewModel.DefaultProfiles}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultProfile, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind Icon, Converter={StaticResource IconSourceConverter}}" />
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind Icon, Converter={StaticResource IconSourceConverter}}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Default Terminal -->
<local:SettingContainer x:Name="DefaultTerminalDropdown"
x:Uid="Globals_DefaultTerminal"
x:Load="false">
<ComboBox x:Name="DefaultTerminal"
ItemsSource="{x:Bind ViewModel.DefaultTerminals}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultTerminal, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:DefaultTerminal">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ColumnSpacing="8">
<!-- Default Terminal -->
<local:SettingContainer x:Name="DefaultTerminalDropdown"
x:Uid="Globals_DefaultTerminal"
x:Load="false">
<ComboBox x:Name="DefaultTerminal"
ItemsSource="{x:Bind ViewModel.DefaultTerminals}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultTerminal, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:DefaultTerminal">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="auto" />
<!-- terminal name and author -->
<ColumnDefinition Width="auto" />
<!-- version -->
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="auto" />
<!-- terminal name and author -->
<ColumnDefinition Width="auto" />
<!-- version -->
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<!-- terminal name -->
<RowDefinition Height="auto" />
<!-- author and version -->
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.RowDefinitions>
<!-- terminal name -->
<RowDefinition Height="auto" />
<!-- author and version -->
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<IconSourceElement Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Width="24"
Height="24"
VerticalAlignment="Center"
IconSource="{x:Bind Icon, Converter={StaticResource IconSourceConverter}}" />
<IconSourceElement Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Width="24"
Height="24"
VerticalAlignment="Center"
IconSource="{x:Bind Icon, Converter={StaticResource IconSourceConverter}}" />
<TextBlock Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
AutomationProperties.AccessibilityView="Raw"
Text="{x:Bind Name}" />
<TextBlock Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
AutomationProperties.AccessibilityView="Raw"
Text="{x:Bind Name}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Author}"
Visibility="{x:Bind local:Converters.StringNotEmptyToVisibility(Author)}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Author}"
Visibility="{x:Bind local:Converters.StringNotEmptyToVisibility(Author)}" />
<TextBlock Grid.Row="1"
Grid.Column="2"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Version}"
Visibility="{x:Bind local:Converters.StringNotEmptyToVisibility(Version)}" />
<TextBlock Grid.Row="1"
Grid.Column="2"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Version}"
Visibility="{x:Bind local:Converters.StringNotEmptyToVisibility(Version)}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Start on User Login -->
<local:SettingContainer x:Uid="Globals_StartOnUserLogin">
<ToggleSwitch IsOn="{x:Bind ViewModel.StartOnUserLogin, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Start on User Login -->
<local:SettingContainer x:Uid="Globals_StartOnUserLogin">
<ToggleSwitch IsOn="{x:Bind ViewModel.StartOnUserLogin, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- First Window Behavior -->
<local:SettingContainer x:Uid="Globals_FirstWindowPreference">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.FirstWindowPreferenceList}"
SelectedItem="{x:Bind ViewModel.CurrentFirstWindowPreference, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Windowing Behavior -->
<local:SettingContainer x:Uid="Globals_WindowingBehavior">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.WindowingBehaviorList}"
SelectedItem="{x:Bind ViewModel.CurrentWindowingBehavior, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Uid="Globals_LaunchSize"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid ColumnSpacing="10"
RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_InitialCols"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialColsBox"
Grid.Row="0"
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialCols, Mode=TwoWay}" />
<TextBlock x:Uid="Globals_InitialRows"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialRowsBox"
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialRows, Mode=TwoWay}" />
</Grid>
</local:SettingContainer>
<!-- Launch Parameters -->
<local:SettingContainer x:Uid="Globals_LaunchParameters"
CurrentValue="{x:Bind ViewModel.LaunchParametersCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_LaunchModeSetting"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center" />
<ComboBox x:Name="LaunchModeComboBox"
Grid.Row="0"
Grid.Column="1"
MinWidth="240"
AutomationProperties.AccessibilityView="Content"
<!-- First Window Behavior -->
<local:SettingContainer x:Uid="Globals_FirstWindowPreference">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.LaunchModeList}"
SelectedItem="{x:Bind ViewModel.CurrentLaunchMode, Mode=TwoWay}"
ItemsSource="{x:Bind ViewModel.FirstWindowPreferenceList}"
SelectedItem="{x:Bind ViewModel.CurrentFirstWindowPreference, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<TextBlock x:Uid="Globals_LaunchPosition"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center" />
<Grid Grid.Row="1"
Grid.Column="1"
ColumnSpacing="4">
</local:SettingContainer>
<!-- Windowing Behavior -->
<local:SettingContainer x:Uid="Globals_WindowingBehavior">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.WindowingBehaviorList}"
SelectedItem="{x:Bind ViewModel.CurrentWindowingBehavior, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Uid="Globals_LaunchSize"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid ColumnSpacing="10"
RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Match the width of these NumberBoxes to the Width of the LaunchModeComboBox above minus the Grid's ColumnSpacing -->
<muxc:NumberBox x:Name="PosXBox"
x:Uid="Globals_InitialPosXBox"
Grid.Row="0"
Grid.Column="0"
Width="118"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosX, Mode=TwoWay}" />
<muxc:NumberBox x:Name="PosYBox"
x:Uid="Globals_InitialPosYBox"
<TextBlock x:Uid="Globals_InitialCols"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialColsBox"
Grid.Row="0"
Grid.Column="1"
Width="118"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosY, Mode=TwoWay}" />
<CheckBox x:Name="UseDefaultLaunchPositionCheckbox"
x:Uid="Globals_DefaultLaunchPositionCheckbox"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
IsChecked="{x:Bind ViewModel.UseDefaultLaunchPosition, Mode=TwoWay}" />
VerticalAlignment="Center"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialCols, Mode=TwoWay}" />
<TextBlock x:Uid="Globals_InitialRows"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialRowsBox"
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialRows, Mode=TwoWay}" />
</Grid>
<TextBlock x:Uid="Globals_CenterOnLaunch"
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center" />
<ToggleSwitch x:Name="CenterOnLaunchToggle"
Grid.Row="2"
</local:SettingContainer>
<!-- Launch Parameters -->
<local:SettingContainer x:Uid="Globals_LaunchParameters"
CurrentValue="{x:Bind ViewModel.LaunchParametersCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_LaunchModeSetting"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center" />
<ComboBox x:Name="LaunchModeComboBox"
Grid.Row="0"
Grid.Column="1"
IsOn="{x:Bind ViewModel.CenterOnLaunch, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
</local:SettingContainer>
MinWidth="240"
AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.LaunchModeList}"
SelectedItem="{x:Bind ViewModel.CurrentLaunchMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<TextBlock x:Uid="Globals_LaunchPosition"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center" />
<Grid Grid.Row="1"
Grid.Column="1"
ColumnSpacing="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Match the width of these NumberBoxes to the Width of the LaunchModeComboBox above minus the Grid's ColumnSpacing -->
<muxc:NumberBox x:Name="PosXBox"
x:Uid="Globals_InitialPosXBox"
Grid.Row="0"
Grid.Column="0"
Width="118"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosX, Mode=TwoWay}" />
<muxc:NumberBox x:Name="PosYBox"
x:Uid="Globals_InitialPosYBox"
Grid.Row="0"
Grid.Column="1"
Width="118"
IsEnabled="{x:Bind local:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosY, Mode=TwoWay}" />
<CheckBox x:Name="UseDefaultLaunchPositionCheckbox"
x:Uid="Globals_DefaultLaunchPositionCheckbox"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
IsChecked="{x:Bind ViewModel.UseDefaultLaunchPosition, Mode=TwoWay}" />
</Grid>
<TextBlock x:Uid="Globals_CenterOnLaunch"
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center" />
<ToggleSwitch x:Name="CenterOnLaunchToggle"
Grid.Row="2"
Grid.Column="1"
IsOn="{x:Bind ViewModel.CenterOnLaunch, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
</local:SettingContainer>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -278,11 +278,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Don't navigate to the same page again.
return;
}
else
{
// If we are navigating to a new page, scroll to the top
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
}
if (const auto navString = clickedItemContainer.Tag().try_as<hstring>())
{
@@ -337,14 +332,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Appearance/Header"), BreadcrumbSubPage::Profile_Appearance);
_breadcrumbs.Append(crumb);
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
}
else if (currentPage == ProfileSubPage::Advanced)
{
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), profile);
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Advanced/Header"), BreadcrumbSubPage::Profile_Advanced);
_breadcrumbs.Append(crumb);
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
}
}
});
@@ -662,8 +655,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_Navigate(newTag.as<hstring>(), BreadcrumbSubPage::None);
}
// Since we are navigating to a new profile after deletion, scroll up to the top
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
}
}

View File

@@ -170,21 +170,18 @@
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer x:Name="SettingsMainPage_ScrollViewer"
Grid.Row="0">
<Frame x:Name="contentFrame"
Grid.Row="0">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition>
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
<DrillInNavigationTransitionInfo />
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
</NavigationThemeTransition>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</ScrollViewer>
<Frame x:Name="contentFrame"
Grid.Row="0">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition>
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
<DrillInNavigationTransitionInfo />
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
</NavigationThemeTransition>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
<!-- Explicitly set the background color on grid to prevent the navigation animation from overflowing it -->
<Grid Grid.Row="1"
Height="55"

View File

@@ -35,114 +35,117 @@
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Suppress Application Title -->
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
ClearSettingValue="{x:Bind Profile.ClearSuppressApplicationTitle}"
HasSettingValue="{x:Bind Profile.HasSuppressApplicationTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.SuppressApplicationTitleOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.SuppressApplicationTitle, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<ScrollViewer Grid.Row="1"
ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Suppress Application Title -->
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
ClearSettingValue="{x:Bind Profile.ClearSuppressApplicationTitle}"
HasSettingValue="{x:Bind Profile.HasSuppressApplicationTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.SuppressApplicationTitleOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.SuppressApplicationTitle, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Antialiasing Mode -->
<local:SettingContainer x:Uid="Profile_AntialiasingMode"
ClearSettingValue="{x:Bind Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.AntiAliasingModeList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentAntiAliasingMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Antialiasing Mode -->
<local:SettingContainer x:Uid="Profile_AntialiasingMode"
ClearSettingValue="{x:Bind Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.AntiAliasingModeList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentAntiAliasingMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- AltGr Aliasing -->
<local:SettingContainer x:Uid="Profile_AltGrAliasing"
ClearSettingValue="{x:Bind Profile.ClearAltGrAliasing}"
HasSettingValue="{x:Bind Profile.HasAltGrAliasing, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.AltGrAliasing, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- AltGr Aliasing -->
<local:SettingContainer x:Uid="Profile_AltGrAliasing"
ClearSettingValue="{x:Bind Profile.ClearAltGrAliasing}"
HasSettingValue="{x:Bind Profile.HasAltGrAliasing, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.AltGrAliasing, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Snap On Input -->
<local:SettingContainer x:Uid="Profile_SnapOnInput"
ClearSettingValue="{x:Bind Profile.ClearSnapOnInput}"
HasSettingValue="{x:Bind Profile.HasSnapOnInput, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.SnapOnInputOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.SnapOnInput, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Snap On Input -->
<local:SettingContainer x:Uid="Profile_SnapOnInput"
ClearSettingValue="{x:Bind Profile.ClearSnapOnInput}"
HasSettingValue="{x:Bind Profile.HasSnapOnInput, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.SnapOnInputOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.SnapOnInput, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- History Size -->
<local:SettingContainer x:Uid="Profile_HistorySize"
ClearSettingValue="{x:Bind Profile.ClearHistorySize}"
HasSettingValue="{x:Bind Profile.HasHistorySize, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.HistorySizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox x:Uid="Profile_HistorySizeBox"
LargeChange="100"
Minimum="0"
SmallChange="10"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind Profile.HistorySize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- History Size -->
<local:SettingContainer x:Uid="Profile_HistorySize"
ClearSettingValue="{x:Bind Profile.ClearHistorySize}"
HasSettingValue="{x:Bind Profile.HasHistorySize, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.HistorySizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox x:Uid="Profile_HistorySizeBox"
LargeChange="100"
Minimum="0"
SmallChange="10"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind Profile.HistorySize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Close On Exit -->
<local:SettingContainer x:Uid="Profile_CloseOnExit"
ClearSettingValue="{x:Bind Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CloseOnExitOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.CloseOnExitModeList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentCloseOnExitMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Close On Exit -->
<local:SettingContainer x:Uid="Profile_CloseOnExit"
ClearSettingValue="{x:Bind Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CloseOnExitOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.CloseOnExitModeList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentCloseOnExitMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Bell Style -->
<local:SettingContainer x:Uid="Profile_BellStyle"
ClearSettingValue="{x:Bind Profile.ClearBellStyle}"
HasSettingValue="{x:Bind Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.BellStyleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_BellStyleAudible"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(1), BindBack=Profile.SetBellStyleAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleWindow"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(2), BindBack=Profile.SetBellStyleWindow, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleTaskbar"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(4), BindBack=Profile.SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Bell Style -->
<local:SettingContainer x:Uid="Profile_BellStyle"
ClearSettingValue="{x:Bind Profile.ClearBellStyle}"
HasSettingValue="{x:Bind Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.BellStyleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_BellStyleAudible"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(1), BindBack=Profile.SetBellStyleAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleWindow"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(2), BindBack=Profile.SetBellStyleWindow, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleTaskbar"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(4), BindBack=Profile.SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
ClearSettingValue="{x:Bind Profile.ClearUseAtlasEngine}"
HasSettingValue="{x:Bind Profile.HasUseAtlasEngine, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAtlasEngineOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.UseAtlasEngine, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
ClearSettingValue="{x:Bind Profile.ClearUseAtlasEngine}"
HasSettingValue="{x:Bind Profile.HasUseAtlasEngine, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAtlasEngineOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.UseAtlasEngine, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- VtPassthrough -->
<local:SettingContainer x:Uid="Profile_VtPassthrough"
ClearSettingValue="{x:Bind Profile.ClearVtPassthrough}"
HasSettingValue="{x:Bind Profile.HasVtPassthrough, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.VtPassthroughOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Profile.VtPassthroughAvailable}">
<ToggleSwitch IsOn="{x:Bind Profile.VtPassthrough, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- VtPassthrough -->
<local:SettingContainer x:Uid="Profile_VtPassthrough"
ClearSettingValue="{x:Bind Profile.ClearVtPassthrough}"
HasSettingValue="{x:Bind Profile.HasVtPassthrough, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.VtPassthroughOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Profile.VtPassthroughAvailable}">
<ToggleSwitch IsOn="{x:Bind Profile.VtPassthrough, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- ReloadEnvVars -->
<local:SettingContainer x:Uid="Profile_ReloadEnvVars"
ClearSettingValue="{x:Bind Profile.ClearReloadEnvironmentVariables}"
HasSettingValue="{x:Bind Profile.HasReloadEnvironmentVariables, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ReloadEnvironmentVariablesOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.ReloadEnvironmentVariables, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- ReloadEnvVars -->
<local:SettingContainer x:Uid="Profile_ReloadEnvVars"
ClearSettingValue="{x:Bind Profile.ClearReloadEnvironmentVariables}"
HasSettingValue="{x:Bind Profile.HasReloadEnvironmentVariables, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ReloadEnvironmentVariablesOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.ReloadEnvironmentVariables, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -41,141 +41,144 @@
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Control Preview -->
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Border x:Name="ControlPreview"
Width="400"
Height="180"
Margin="0,0,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
</Border>
<ScrollViewer Grid.Row="1"
ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Control Preview -->
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Border x:Name="ControlPreview"
Width="400"
Height="180"
Margin="0,0,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
</Border>
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
<!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_TransparencyHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_TransparencyHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Opacity -->
<local:SettingContainer x:Name="OpacityContainer"
x:Uid="Profile_Opacity"
ClearSettingValue="{x:Bind Profile.ClearOpacity}"
HasSettingValue="{x:Bind Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.OpacityOverrideSource, Mode=OneWay}">
<StackPanel x:Name="OpacityControl">
<!-- Opacity -->
<local:SettingContainer x:Name="OpacityContainer"
x:Uid="Profile_Opacity"
ClearSettingValue="{x:Bind Profile.ClearOpacity}"
HasSettingValue="{x:Bind Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.OpacityOverrideSource, Mode=OneWay}">
<StackPanel x:Name="OpacityControl">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="OpacitySlider"
x:Uid="Profile_OpacitySlider"
Grid.Column="0"
Value="{x:Bind local:Converters.PercentageToPercentageValue(Profile.Opacity), BindBack=Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind local:Converters.AppendPercentageSign(OpacitySlider.Value), Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic"
ClearSettingValue="{x:Bind Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAcrylicOverrideSource, Mode=OneWay}">
<ToggleSwitch x:Name="UseAcrylicToggleSwitch"
IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Window -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_WindowHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Padding -->
<local:SettingContainer x:Uid="Profile_Padding"
ClearSettingValue="{x:Bind Profile.ClearPadding}"
HasSettingValue="{x:Bind Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.PaddingOverrideSource, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="OpacitySlider"
x:Uid="Profile_OpacitySlider"
<Slider x:Name="PaddingSlider"
x:Uid="Profile_PaddingSlider"
Grid.Column="0"
Value="{x:Bind local:Converters.PercentageToPercentageValue(Profile.Opacity), BindBack=Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
Value="{x:Bind local:Converters.MaxValueFromPaddingString(Profile.Padding), BindBack=Profile.SetPadding, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind local:Converters.AppendPercentageSign(OpacitySlider.Value), Mode=OneWay}" />
Text="{Binding ElementName=PaddingSlider, Path=Value, Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
</local:SettingContainer>
<!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic"
ClearSettingValue="{x:Bind Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAcrylicOverrideSource, Mode=OneWay}">
<ToggleSwitch x:Name="UseAcrylicToggleSwitch"
IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Window -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_WindowHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Padding -->
<local:SettingContainer x:Uid="Profile_Padding"
ClearSettingValue="{x:Bind Profile.ClearPadding}"
HasSettingValue="{x:Bind Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.PaddingOverrideSource, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="PaddingSlider"
x:Uid="Profile_PaddingSlider"
Grid.Column="0"
Value="{x:Bind local:Converters.MaxValueFromPaddingString(Profile.Padding), BindBack=Profile.SetPadding, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=PaddingSlider, Path=Value, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
<StackPanel MaxWidth="{StaticResource StandardControlMaxWidth}">
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind Profile.EditableUnfocusedAppearance, Mode=OneWay}">
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
Style="{StaticResource TitleTextBlockStyle}" />
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
Margin="10,0,0,0"
Click="CreateUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon Margin="0,3,0,0"
FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="Profile_AddAppearanceButton"
Margin="10,0,0,0"
FontSize="{StaticResource StandardIconSize}" />
</StackPanel>
</Button.Content>
</Button>
<Button x:Uid="Profile_DeleteUnfocusedAppearanceButton"
Margin="10,0,0,0"
Click="DeleteUnfocusedAppearance_Click"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind Profile.HasUnfocusedAppearance, Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteAppearanceButton"
Margin="10,0,0,0"
FontSize="{StaticResource StandardIconSize}" />
</StackPanel>
</Button.Content>
</Button>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
<StackPanel MaxWidth="{StaticResource StandardControlMaxWidth}">
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind Profile.EditableUnfocusedAppearance, Mode=OneWay}">
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
Style="{StaticResource TitleTextBlockStyle}" />
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
Margin="10,0,0,0"
Click="CreateUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon Margin="0,3,0,0"
FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="Profile_AddAppearanceButton"
Margin="10,0,0,0"
FontSize="{StaticResource StandardIconSize}" />
</StackPanel>
</Button.Content>
</Button>
<Button x:Uid="Profile_DeleteUnfocusedAppearanceButton"
Margin="10,0,0,0"
Click="DeleteUnfocusedAppearance_Click"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind Profile.HasUnfocusedAppearance, Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteAppearanceButton"
Margin="10,0,0,0"
FontSize="{StaticResource StandardIconSize}" />
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
<local:Appearances Appearance="{x:Bind Profile.UnfocusedAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}"
Visibility="{x:Bind Profile.ShowUnfocusedAppearance, Mode=OneWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
</StackPanel>
<local:Appearances Appearance="{x:Bind Profile.UnfocusedAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}"
Visibility="{x:Bind Profile.ShowUnfocusedAppearance, Mode=OneWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -52,6 +52,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DeleteButton().Focus(FocusState::Programmatic);
_Profile.FocusDeleteButton(false);
ProfilesBase_ScrollView().ChangeView(nullptr, ProfilesBase_ScrollView().ScrollableHeight(), nullptr);
}
});
}

View File

@@ -31,161 +31,165 @@
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Style="{StaticResource SettingsStackStyle}">
<ScrollViewer Name="ProfilesBase_ScrollView"
Grid.Row="1"
ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Uid="Profile_Name"
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Uid="Profile_Name"
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="CommandlineContainer"
x:Uid="Profile_Commandline"
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<StackPanel>
<TextBox x:Uid="Profile_CommandlineBox"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Margin="0,10,0,0"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectoryContainer"
x:Uid="Profile_StartingDirectory"
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
CurrentValue="{x:Bind Profile.StartingDirectory, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Vertical">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<StackPanel Orientation="Horizontal">
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Margin="0,10,10,0"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
<!-- Commandline -->
<local:SettingContainer x:Name="CommandlineContainer"
x:Uid="Profile_Commandline"
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<StackPanel>
<TextBox x:Uid="Profile_CommandlineBox"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Margin="0,10,0,0"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
Margin="0,5,0,0"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</StackPanel>
</local:SettingContainer>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind Profile.ClearIcon}"
CurrentValue="{x:Bind Profile.Icon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<TextBox x:Uid="Profile_IconBox"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Icon, Mode=TwoWay}" />
<Button x:Uid="Profile_IconBrowse"
Margin="0,10,0,0"
Click="Icon_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Tab Title -->
<local:SettingContainer x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
CurrentValue="{x:Bind Profile.TabTitle, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Elevate -->
<local:SettingContainer x:Uid="Profile_Elevate"
ClearSettingValue="{x:Bind Profile.ClearElevate}"
HasSettingValue="{x:Bind Profile.HasElevate, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ElevateOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Elevate, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
Margin="0,48,0,0"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<Button x:Name="AppearanceNavigator"
Click="Appearance_Click"
Style="{StaticResource NavigatorButtonStyle}">
Appearance
</Button>
<Button x:Name="AdvancedNavigator"
Click="Advanced_Click"
Style="{StaticResource NavigatorButtonStyle}">
<TextBlock HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="Advanced" />
</Button>
<!-- Delete Button -->
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Button x:Name="DeleteButton"
Margin="{StaticResource StandardControlMargin}"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind Profile.CanDeleteProfile}">
<Button.Content>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectoryContainer"
x:Uid="Profile_StartingDirectory"
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
CurrentValue="{x:Bind Profile.StartingDirectory, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Vertical">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Margin="0,10,10,0"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
Margin="0,5,0,0"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Profile_DeleteConfirmationButton"
Click="DeleteConfirmation_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</StackPanel>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind Profile.ClearIcon}"
CurrentValue="{x:Bind Profile.Icon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<TextBox x:Uid="Profile_IconBox"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Icon, Mode=TwoWay}" />
<Button x:Uid="Profile_IconBrowse"
Margin="0,10,0,0"
Click="Icon_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Tab Title -->
<local:SettingContainer x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
CurrentValue="{x:Bind Profile.TabTitle, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Elevate -->
<local:SettingContainer x:Uid="Profile_Elevate"
ClearSettingValue="{x:Bind Profile.ClearElevate}"
HasSettingValue="{x:Bind Profile.HasElevate, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ElevateOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Elevate, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
Margin="0,48,0,0"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<Button x:Name="AppearanceNavigator"
Click="Appearance_Click"
Style="{StaticResource NavigatorButtonStyle}">
Appearance
</Button>
</Border>
</StackPanel>
<Button x:Name="AdvancedNavigator"
Click="Advanced_Click"
Style="{StaticResource NavigatorButtonStyle}">
<TextBlock HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="Advanced" />
</Button>
<!-- Delete Button -->
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Button x:Name="DeleteButton"
Margin="{StaticResource StandardControlMargin}"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind Profile.CanDeleteProfile}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Profile_DeleteConfirmationButton"
Click="DeleteConfirmation_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -18,26 +18,28 @@
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<TextBlock x:Uid="Globals_RenderingDisclaimer"
Style="{StaticResource DisclaimerStyle}" />
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<TextBlock x:Uid="Globals_RenderingDisclaimer"
Style="{StaticResource DisclaimerStyle}" />
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAtlasEngine, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAtlasEngine, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Force Full Repaint -->
<local:SettingContainer x:Uid="Globals_ForceFullRepaint">
<ToggleSwitch IsOn="{x:Bind ViewModel.ForceFullRepaintRendering, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Force Full Repaint -->
<local:SettingContainer x:Uid="Globals_ForceFullRepaint">
<ToggleSwitch IsOn="{x:Bind ViewModel.ForceFullRepaintRendering, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Software Rendering -->
<local:SettingContainer x:Uid="Globals_SoftwareRendering">
<ToggleSwitch IsOn="{x:Bind ViewModel.SoftwareRendering, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Software Rendering -->
<local:SettingContainer x:Uid="Globals_SoftwareRendering">
<ToggleSwitch IsOn="{x:Bind ViewModel.SoftwareRendering, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</Page>

View File

@@ -59,7 +59,6 @@ namespace
HRESULT PaintBufferLine(std::span<const Cluster> /*clusters*/, til::point /*coord*/, bool /*fTrimLeft*/, bool /*lineWrapped*/) noexcept { return S_OK; }
HRESULT PaintBufferGridLines(GridLineSet /*lines*/, COLORREF /*gridlineColor*/, COLORREF /*underlineColor*/, size_t /*cchLine*/, til::point /*coordTarget*/) noexcept { return S_OK; }
HRESULT PaintSelection(const til::rect& /*rect*/) noexcept { return S_OK; }
HRESULT PaintSelections(const std::vector<til::rect>& /*rects*/) noexcept { return S_OK; }
HRESULT PaintCursor(const CursorOptions& /*options*/) noexcept { return S_OK; }
HRESULT UpdateDrawingBrushes(const TextAttribute& /*textAttributes*/, const RenderSettings& /*renderSettings*/, gsl::not_null<IRenderData*> /*pData*/, bool /*usingSoftFont*/, bool /*isSettingDefaultBrushes*/) noexcept { return S_OK; }
HRESULT UpdateFont(const FontInfoDesired& /*FontInfoDesired*/, _Out_ FontInfo& /*FontInfo*/) noexcept { return S_OK; }

View File

@@ -19,6 +19,7 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="inc\SafeDispatcherTimer.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="inc\ScopedResourceLoader.h" />
<ClInclude Include="inc\LibraryResources.h" />
@@ -52,4 +53,4 @@
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
</Project>
</Project>

View File

@@ -2,21 +2,21 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="LibraryResources.cpp" />
<ClCompile Include="ScopedResourceLoader.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="ScopedResourceLoader.h" />
<ClInclude Include="inc\LibraryResources.h" />
<ClInclude Include="inc\SafeDispatcherTimer.h" />
<ClInclude Include="inc\ScopedResourceLoader.h" />
<ClInclude Include="inc\ThrottledFunc.h" />
<ClInclude Include="inc\Utils.h" />
<ClInclude Include="inc\WtExeUtils.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
// Par for the course, the XAML timer class is "self-referential". Releasing all references
// to an instance will not stop the timer. Only calling Stop() explicitly will achieve that.
struct SafeDispatcherTimer
{
SafeDispatcherTimer() = default;
SafeDispatcherTimer(SafeDispatcherTimer const&) = delete;
SafeDispatcherTimer& operator=(SafeDispatcherTimer const&) = delete;
SafeDispatcherTimer(SafeDispatcherTimer&&) = delete;
SafeDispatcherTimer& operator=(SafeDispatcherTimer&&) = delete;
~SafeDispatcherTimer()
{
Destroy();
}
explicit operator bool() const noexcept
{
return _timer != nullptr;
}
winrt::Windows::Foundation::TimeSpan Interval()
{
return _getTimer().Interval();
}
void Interval(winrt::Windows::Foundation::TimeSpan const& value)
{
_getTimer().Interval(value);
}
bool IsEnabled()
{
return _timer && _timer.IsEnabled();
}
void Tick(winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable> const& handler)
{
auto& timer = _getTimer();
if (_token)
{
timer.Tick(_token);
}
_token = timer.Tick(handler);
}
void Start()
{
_getTimer().Start();
}
void Stop() const
{
if (_timer)
{
_timer.Stop();
}
}
void Destroy()
{
if (!_timer)
{
return;
}
_timer.Stop();
if (_token)
{
_timer.Tick(_token);
}
_timer = nullptr;
_token = {};
}
private:
::winrt::Windows::UI::Xaml::DispatcherTimer& _getTimer()
{
if (!_timer)
{
_timer = ::winrt::Windows::UI::Xaml::DispatcherTimer{};
}
return _timer;
}
::winrt::Windows::UI::Xaml::DispatcherTimer _timer{ nullptr };
winrt::event_token _token;
};

Some files were not shown because too many files have changed in this diff Show More