Compare commits

...

249 Commits

Author SHA1 Message Date
Dustin L. Howett
476ce69549 Migrate spelling-0.0.21 changes from main 2022-04-15 00:05:33 +02:00
Leonard Hecker
9bda600138 Another attempt at fixing nearby font loading (#12904)
The original research for a solution all the way back in #11032 contained an
unfortunate flaw. The nearby font loading code was written under the assumption
that Cascadia is missing in the system font collection, leading to our issues.
Adding nearby fonts last into the collection would thus ensure that we use
the system fonts whenever possible, but only have nearby fonts as a fallback.

This didn't work and we figured that we'd have to always prefer loading nearby
fonts over system fonts. #12554 tried to achieve this, but failed to change
the order in which the font set is built. In order to prefer nearby fonts
over system ones, we have to add the system font collection last.

## PR Checklist

* [x] Closes #11648
* [x] I work here
* [x] Tests added/passed
* [x] Embarrassment for my incompetence

## Validation Steps Performed

* Put Jetbrains Mono into the AppX directory of the Debug build
* Jetbrains Mono shows up in the font selector and is useable

Additionally a more complex mini-test was built:
Using FontForge I've cloned arial.ttf and removed all characters except for
the letter "0". Afterwards I've build a custom font collection the same way
we do it in Terminal, extracted a `FontFace` named "Arial" and called
`IDWriteFont::HasCharacter` for the letter "1".
Loading the system font collection first results in `TRUE` and loading it last
results in `FALSE` (since my custom arial.ttf doesn't have the letter "1").
This confirms that we need to load the system font collection last.

(cherry picked from commit eeb8970c6c)
Service-Card-Id: 80641213
Service-Version: 1.12
2022-04-21 17:06:35 -05:00
Mike Griese
e9b4e2e18f Remove default_interface from Monarch (#12856)
This is all of course, conjecture. This crash is totally wild and makes no sense at all. But, we're hoping that this fixes it. This should also make calls to the Monarch a little easier.

You may be asking yourself - why aren't I doing this for the Peasant too? Well, because the Peasant simply doesn't crash like the monarch does. I'm not gonna touch something that's not broken _during ask mode_.

References #12774. We can close the bug if it is verified fixed.

(cherry picked from commit b64fd774ce)
Service-Card-Id: 80383092
Service-Version: 1.12
2022-04-08 14:07:12 -05:00
Leonard Hecker
cd57f2c24e Fix DBCS attribute corruption during reflow (#12853)
855e136 contains a regression which breaks buffer reflow if wide surrogate
characters are present. This happens because we made use of the
`TextBufferCellIterator` whose increment operator skips 2 cells for wide
characters. This created a "misalignment" in the reflow logic which was written
for cell-wise iteration. This commit fixes the issue, by reverting back to the
previous algorithm without iterators.

Closes #12837
Closes MSFT-38904421

## Validation Steps Performed
* Run ``pwsh -noprofile -command echo "`u{D83D}`u{DE43}"``
* Resizing conhost preserves all contents 
* Resizing Windows Terminal doesn't crash it 
* Added a test covering this issue 

(cherry picked from commit 10b9044120)
Service-Card-Id: 80340089
Service-Version: 1.12
2022-04-08 12:30:12 -05:00
Mike Griese
36ba83b8d7 Manually focus the scheme dropdown when deleting a scheme (#12841)
If we delete a scheme, and the next scheme we've loaded is an inbox one
that _can't_ be deleted, then we need to toss focus to something
sensible, rather than letting it fall out to the tab item.

When deleting a scheme and the next scheme _is_ deletable, this isn't an
issue, we'll already correctly focus the Delete button.

125e9c4790 focused the SelectionBackground
button, which is the _previous_ focusable control, rather than the
following one.

However, it seems even more useful for focus to ALWAYS land on the
scheme dropdown box. This forces Narrator to read the name of the newly
selected color scheme, which seemed more useful.

I'm waiting on feedback from a11y team to see if this solution is
acceptable.

* [x] Is for #11971

(cherry picked from commit 866d22e3a1)
Service-Card-Id: 80283574
Service-Version: 1.12
2022-04-07 15:24:53 -05:00
Dustin L. Howett
fed783858f Upgrade WinUI2 to 2.7.1 (#12847)
This fixes a number of issues including a NavigationView crash.

(cherry picked from commit cdffc99f76)
Service-Card-Id: 80283211
Service-Version: 1.12
2022-04-06 17:39:50 -05:00
Mike Griese
d0dfcad842 Manually put our ContentDialogs in the tab content, rather than above (#12840)
After switching to ControlsV2, it seems that
delay-loading a dialog causes the ContentDialog to be assigned a
Height equal to it's content size. If we DON'T assign the
ContentDialog a Row, I believe it's assigned Row 0 by default. So,
when the dialog gets opened, the dialog seemingly causes a giant
hole to appear in the body of the app.

Assigning all the dialogs to Row 2 (where the rest of the content
is) makes the "hole" appear in the same space as the rest of the
TabContent, fixing the issue.

Note that the actual content in a content dialog gets parented to
the PopupRoot, so it actually always appeared in the correct place, it's
just this weird hole that appeared in Row 0.

* [x] Closes #12775
  * See also:
    * #12202 was fixed by #12208
    * #12447 was fixed by #12517
* [x] Tested manually
* [x] Reverts #12625
* [x] Reverts #12517

(cherry picked from commit c4e5ebf238)
Service-Card-Id: 80266902
Service-Version: 1.12
2022-04-06 17:37:36 -05:00
Mike Griese
26f5496957 Make sure we have a sensible HC color for the titlebar (#12839)
You'd think that if a key wasn't present in a ThemeDictionary, it'd fall back to the original value. You'd be wrong - if you provide a Light&dark version of a resource, but not the HighContrast version, the resource loader will fall back to the _Light_ value. Of course.

Before (left top), after (right bottom)
![image](https://user-images.githubusercontent.com/18356694/161997751-2ed8d053-488a-47fa-a289-8d7b465bd0b0.png)

Closes MSFT:38264744

(cherry picked from commit 475b38a905)
Service-Card-Id: 80264531
Service-Version: 1.12
2022-04-06 13:41:52 -05:00
Mike Griese
055d0b8937 Cache ProposeCommandlineResult locally (#12838)
This is like, 2-4% of our crashes. Impossible to say for sure, but this _looks_ like it's the root cause. This is just another one of our `HandleCommandlineArgs` buckets, hopefully the last.

* [x] Hopefully should close out MSFT:38542548
* [ ] No I didn't write tests, impossible to test
* [x] it builds

(cherry picked from commit 89bbbb8d6b)
Service-Card-Id: 80261873
Service-Version: 1.12
2022-04-06 13:41:50 -05:00
Mike Griese
5224c88eaf Try to silently fall back to a local monarch (#12825)
This is a crazy idea Dustin and I had.

> we can't repro this at will. But we kinda have an idea of where the deref is. We don't know if the small patch (throw, and try again) will fix it. We're sure that the "just fall back to an isolated monarch" will work. I'd almost rather take a build testing the small patch first, to see if that works

> This might seem crazy
> in 1.12, isolated monarch. In 1.13, "small patch". In 1.14, we can wait and see

I can write more details in the morning. It's 5pm here so if we want this today, here it is.

@dhowett double check my velocity flag logic here. Should be always true for Release, and off for Dev, Preview.

* [x] closes #12774

(cherry picked from commit 446f280757)
Service-Card-Id: 80154584
Service-Version: 1.12
2022-04-04 17:38:11 -05:00
Dustin L. Howett
43755ea78a Autocomplete keyframe animations when occluded on Windows 11 (#12820)
On certain builds of Windows, when Terminal is set as the default it
will accumulate an unbounded amount of queued animations while the
screen is off and it is servicing window management for console
applications.

This results in Terminal hanging when left overnight, as it has millions
of animations to process.

The new call into TerminalThemeHelpers will tell our compositor to
automatically complete animations that are scheduled while the screen is
off.

Fixes MSFT-38506980

(cherry picked from commit 8405c7a697)
Service-Card-Id: 80150450
Service-Version: 1.12
2022-04-04 17:35:02 -05:00
Dustin L. Howett
48ba2c0766 Force the bundle major version to be over 3000 (#12819)
Before #12691, the msixbundle version was of the format YYYY.MM.DD.0.
After #12691, it became the same as the build of Terminal it contained.

This caused some trouble for _some_ systems: major version 1 is much,
much smaller than 2022.

Adding 3000 to the major version component, _only for the bundle_, gets
around this. Ugh.

Fixes #12816.

(cherry picked from commit bc6bf15a62)
Service-Card-Id: 80144496
Service-Version: 1.12
2022-04-04 17:33:43 -05:00
Mike Griese
28443c2302 Auto-focus window renamer textbox on open (#12798)
Does what it says on the tin. This is maximal BODGE.

`TeachingTip` doesn't provide an `Opened` event.
(https://github.com/microsoft/microsoft-ui-xaml/issues/1607). But we
want to focus the renamer text box when it's opened. We can't do that
immediately, the TextBox technically isn't in the visual tree yet. We
have to wait for it to get added some time after we call IsOpen. How do
we do that reliably? Usually, for this kind of thing, we'd just use a
one-off LayoutUpdated event, as a notification that the TextBox was
added to the tree. HOWEVER:
* The _first_ time this is fired, when the box is _first_ opened,
  yeeting focus doesn't work on the first LayoutUpdated. It does work on
  the second LayoutUpdated. Okay, so we'll wait for two LayoutUpdated
  events, and focus on the second.
* On subsequent opens: We only ever get a single LayoutUpdated. Period.
  But, you can successfully focus it on that LayoutUpdated.

So, we'll keep track of how many LayoutUpdated's we've _ever_ gotten. If
we've had at least 2, then we can focus the text box.

We're also not using a ContentDialog for this, because in Xaml Islands a
text box in a ContentDialog won't receive _any_ keypresses. Fun!

## References
* microsoft/microsoft-ui-xaml#1607
* microsoft/microsoft-ui-xaml#6910
* microsoft/microsoft-ui-xaml#3257
* microsoft/terminal#9662

## PR Checklist
* [x] Will close out #12021, but that's an a11y bug that needs secondary
  validation
* [x] Closes #11322
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated

## Validation Steps Performed

Tested manually

(cherry picked from commit b57fe85997)
Service-Card-Id: 79978833
Service-Version: 1.12
2022-03-31 13:28:53 -05:00
Dustin L. Howett
013b19c377 Build PublicTerminalCore for ARM64, and package it with WPF (#12787)
I also took the opportunity to clean up the WPF stage's artifact rules.

Closes #12786

(cherry picked from commit 0651d92dba)
Service-Card-Id: 79856465
Service-Version: 1.12
2022-03-29 15:09:10 -05:00
Dustin L. Howett
f8685647bb Add mp:PhoneIdentity to stop Store from rewriting our packages (#12779)
If we do not include mp:PhoneIdentity in our AppxManifest, the store
will edit our package and re-sign it for distribution. When that
happens, it creates a divergence: there are now two versions of our
package with the same name and version number, but different contents.

This breaks everything.

**THIS IS LOAD BEARING**

(cherry picked from commit 0bc66abd3b)
2022-03-28 17:29:00 -05:00
Mike Griese
aa9fe1c32a Manually copy trailing attributes on a resize (#12637)
## THE WHITE WHALE

This is a fairly naive fix for this bug. It's not terribly performant,
but neither is resize in the first place.

When the buffer gets resized, typically we only copy the text up to the
`MeasureRight` point, the last printable char in the row. Then we'd just
use the last char's attributes to fill the remainder of the row.

Instead, this PR changes how reflow behaves when it gets to the end of
the row. After we finish copying text, then manually walk through the
attributes at the end of the row, and copy them over. This ensures that
cells that just have a colored space in them get copied into the new
buffer as well, and we don't just blat the last character's attributes
into the rest of the row. We'll do a similar thing once we get to the
last printable char in the buffer, copying the remaining attributes.

This could DEFINITELY be more performant. I think this current
implementation walks the attrs _on every cell_, then appends the new
attrs to the new ATTR_ROW. That could be optimized by just using the
actual iterator. The copy after the last printable char bit is also
especially bad in this regard. That could likely be a blind copy - I
just wanted to get this into the world.

Finally, we now copy the final attributes to the correct buffer: the new
one.  We used to copy them to the _old_ buffer, which we were about to
destroy.

## Validation

I'll add more gifs in the morning, not enough time to finish spinning a
release Terminal build with this tonight.

Closes #32 🎉🎉🎉🎉🎉🎉🎉🎉🎉
Closes #12567

(cherry picked from commit 855e1360c0)
2022-03-28 17:28:58 -05:00
Dustin Howett
0ec3c7268c Fix build break from fcdf02b2bf 2022-03-28 14:46:55 -05:00
PankajBhojwani
20041297e9 Add tooltips for nav items in the SUI (#12448)
## Summary of the Pull Request
Profiles with long names were having their titles cut off in the navigation view sidebar. This change adds tooltips to all nav view items so the full names can still be read.

## References
#11353

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x[ I work here

## Validation Steps Performed
<img width="261" alt="sidebartooltip" src="https://user-images.githubusercontent.com/26824113/153270004-02ec3ca7-8787-41be-a4ee-c60efa8cc5e6.png">
<img width="341" alt="sidebartooltip2" src="https://user-images.githubusercontent.com/26824113/153270033-263069f6-75ff-4215-9c83-e0a946ce9616.png">

(cherry picked from commit 19a5eb208d)
2022-03-28 14:23:09 -05:00
Dan Mezhiborsky
ff7384b3db Fix transparency/opacity inconsistency in help text (#12592) (#12727)
In two instances, the help text for the settings UI refers to _transparency_ when we're really talking about _opacity._ This PR changes those occurences to more accurately reflect the setting being described.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #12592

(cherry picked from commit f5882236dc)
2022-03-28 12:32:17 -05:00
Dustin L. Howett
875d7ac97e Hush a garrulous event from TerminalControl (#12723)
Fixes MSFT-36708760

(cherry picked from commit 2de2ae2362)
2022-03-28 12:26:35 -05:00
Leonard Hecker
a8d7d8ce04 Fix exception spam if UIA is running (#12698)
`std::basic_string_view::substr` throws an exception if the first argument
(offset) is out of range. If UIA is running, this creates _a lot_ of exceptions
and associated log output. This trivial change takes care of that.

(cherry picked from commit e5b5af5186)
2022-03-28 12:26:34 -05:00
Leonard Hecker
fcdf02b2bf Allow fragments to override the name of new profiles (#12627)
After this commit we only set the default fields of a profile - primarily the
name field - as late as possible, after layering has already completed.
This ensures that we pick up any modifications from fragments.

* [x] Closes #12520
* [x] I work here
* [x] Tests added/passed

* Add a fragment at
  `%LocalAppData%\Microsoft\Windows Terminal\Fragments\Fragment\fragment.json`
  with
  `{"profiles":[{"updates":"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}","name":"NewName"}]}`
* Windows PowerShell profile is created with the name "NewName" in settings.json 

(cherry picked from commit ee83081b64)
2022-03-28 12:26:34 -05:00
Dustin L. Howett
89fa517735 Fix engine size not being changed on DPI changes (#12749)
Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
2022-03-24 12:53:20 -05:00
Leonard Hecker
8aeb525d73 DxEngine: Fix shader compilation on pre-D3D11 hardware (#12677)
* Drop engine support for DirectX 9.1
  Practically no one has such old hardware anymore and AtlasEngine additionally
  drops support for 10.0. The fallback also didn't work properly,
  because the `FeatureLevels` array failed to include 9.2 and 9.3.
  We'll simply fall back to WARP on all such devices.
* Optimize shaders during compilation
  The two new flags increase shader performance sometimes significantly.
* Fix shader feature level flags
  D3D feature level 10.0 only support 4.0 and 10.1 only 4.1 shaders.

## PR Checklist
* [x] Closes #12655
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* Add `WindowsTerminal.exe` in `dxcpl.exe`
* Add a basic `experimental.pixelShaderPath`
* All forced feature levels between `9_1` and `11_1` render as expected 

(cherry picked from commit d5fb7369cb)
2022-03-15 15:35:03 -05:00
Dustin Howett
c903c0e410 Fix an issue presenting the initial appearance preview
Signed-off-by: Mike Griese <migrie@microsoft.com>
2022-03-15 15:02:32 -05:00
Dustin Howett
95b8cf50c3 Fix build break from f42ff55d2 2022-03-15 14:48:25 -05:00
Mike Griese
57fe08aae1 When we delete a profile, focus the delete button automatically (#12558)
This sure is bodgy, but it makes sense. Right now, when we delete a profile, we load in a totally new content for the new profile's settings. That one resets the scroll view and the focus, and now the "delete" button is obviously not focused.

Instead, this PR will manually re-focus the delete button of a profile page when the page is navigated to _because we deleted another profile_.

* [x] This will take care of #11971

(cherry picked from commit 7fdcd6f5b3)
2022-03-15 14:09:34 -05:00
Leonard Hecker
f42ff55d2d Fix Windows 10 support for nearby font loading (#12554)
By replacing `IDWriteFontSetBuilder2::AddFontFile` with
`IDWriteFactory5::CreateFontFileReference` and
`IDWriteFontSetBuilder1::AddFontFile` we add nearby
font loading support for Windows 10, build 15021.

This commit also fixes font fallback for AtlasEngine,
which was crashing during testing.

Finally it fixes a bug in DxEngine, where we only created a "nearby" font
collection if we couldn't find the font in the system collection. This doesn't
fix the bug, if the font is locked or broken in the system collection.

This is related to #11648.

* [x] Closes #12420
* [x] I work here
* [x] Tests added/passed

* Build a Debug version of Windows Terminal
* Put Jetbrains Mono into the writeable AppX directory
* Jetbrains Mono is present in the settings UI 
* DxEngine works with Jetbrains Mono 
* AtlasEngine works with Jetbrains Mono 

(cherry picked from commit f84ccad42d)
2022-03-15 14:09:34 -05:00
Sergey
fca9d58d6c Adds exception handling of uri creation in profile background image update (#11542)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Moves baskgroung image update releated code into separate function and adds uri path construction exeption handling.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #11361
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Tried to put garbage as a path. Terminal didn't crashed.

(cherry picked from commit f63159db59)
2022-03-15 14:06:19 -05:00
Dustin Howett
3ad42b4c15 Merge the Windows 11 UI Rejuv into 1.12 (#12696) 2022-03-15 14:03:20 -05:00
Mike Griese
e9955368ee Round our Maximize button to match ControlsV2 styles (#12660)
Just look at the screenshot. Above is before, below is now.
![image](https://user-images.githubusercontent.com/18356694/157717931-f3e3167e-0234-425a-a8eb-02303f386dc6.png)

These paths were taken straight from WinUI versions of these icons, thanks @pratikone for the alley oop.

* [x] Closes #12433
* [x] Tested manually by _lookin at it_
2022-03-15 12:15:15 -05:00
Dustin L. Howett
ad3de53dec Fix the appxbundle version to be the appx version (#12691)
The store did not like when I uploaded two Windows Terminal packages
built on the same date, because the appxbundle version defaulted to
YYYY.MMDD.something.

There was a risk that using *this* version number will fail because it is
thousands of numbers less than "2022". We'll have to see if the store
rolls it out properly. I cannot find any documentation on how the store
rolls out *bundle* versions (it is very aware of .appx versions...).

A local test with 1.14.72x (Preview) published via the store seems to
have worked.

(cherry picked from commit a5194b0c44)
2022-03-14 13:53:33 -05:00
Leonard Hecker
92599d0a67 Fix "Element not found" error during settings loading (#12687)
This commit fixes a stray exception during settings loading,
caused by a failure to obtain the app's extension catalog.

## PR Checklist
* [x] Closes #12305
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
I'm unable to replicate the issue. 
However an error log was provided in #12305 with which
the function causing the exception could be determined.

(cherry picked from commit 9c6ec75082)
2022-03-14 12:07:20 -05:00
Dustin Howett
20a6de0042 This will be a build break in UIA - Fix it 2022-03-11 18:05:06 -06:00
Carlos Zamora
d452399921 Use UIA notifications for text output (#12358)
This change makes Windows Terminal raise a `RaiseNotificationEvent()` ([docs](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.automation.peers.automationpeer.raisenotificationevent?view=winrt-22000)) for new text output to the buffer.

This is intended to help Narrator identify what new output appears and reduce the workload of diffing the buffer when a `TextChanged` event occurs.

The flow of the event occurs as follows:
- `Terminal::_WriteBuffer()`
   - New text is output to the text buffer. Notify the renderer that we have new text (and what that text is).
- `Renderer::TriggerNewTextNotification()`
   - Cycle through all the rendering engines and tell them to notify handle the new text output.
   - None of the rendering engines _except_ `UiaEngine` has it implemented, so really we're just notifying UIA.
- `UiaEngine::NotifyNewText()`
   - Concatenate any new output into a string.
   - When we're done painting, tell the notification system to actually notify of new events occurring and clear any stored output text. That way, we're ready for the next renderer frame.
- `InteractivityAutomationPeer::NotifyNewOutput()` --> `TermControlAutomationPeer::NotifyNewOutput`
   - NOTE: these are split because of the in-proc and out-of-proc separation of the buffer.
   - Actually `RaiseNotificationEvent()` for the new text output.

Additionally, we had to handle the "local echo" problem: when a key is pressed, the character is said twice (once for the keyboard event, and again for the character being written to the buffer). To accomplish this, we did the following:
- `TermControl`:
   - here, we already handle keyboard events, so I added a line saying "if we have an automation peer attached, record the keyboard event in the automation peer".
- `TermControlAutomationPeer`:
   - just before the notification is dispatched, check if the string of recent keyboard events match the beginning of the string of new output. If that's the case, we can assume that the common prefix was the "local echo".

This is a fairly naive heuristic, but it's been working.

Closes the following ADO bugs:
- https://dev.azure.com/microsoft/OS/_workitems/edit/36506838
- (Probably) https://dev.azure.com/microsoft/OS/_workitems/edit/38011453

- [x] Base case: "echo hello"
- [x] Partial line change
- [x] Scrolling (should be unaffected)
- [x] Large output
- [x] "local echo": keyboard events read input character twice

(cherry picked from commit f9be1720bd)
2022-03-11 17:58:25 -06:00
Leonard Hecker
fa214254a9 Fix overflow in Viewport::FromDimensions (#12669)
This removes one source of potential integer overflows from the Viewport class.
Other parts were left untouched, as this entire class of overflow issues gets
 fixed all at once, as soon as we replace COORD with til::coord (etc.).

* [x] Closes #5271
* [x] I work here
* [x] Tests added/passed

* Call `ScrollConsoleScreenBufferW` with out of bounds coordinates
* Doesn't crash 

(cherry picked from commit a4a6dfcc8d)
2022-03-11 15:30:15 -06:00
Mike Griese
a7b9e9b583 Fix a pair of crashes, likely related to defterm (#12666)
This fixes a pair of inbox bugs, hopefully.

* MSFT:35731327
  * There's a small window where a peasant is being created when a monarch is exiting. When that happens, the new peasant will try to tell itself (the new monarch) when the peasant was last activated, but because the window hasn't actually finished instantiating, the peasant doesn't yet have a LastActivatedArgs to tell the monarch about.
* MSFT:32518679 (ARM version) / MSFT:32279047 (AMD64 version)
  * This one's tricky. Not totally sure this is the fix, bug assuming my hypothesis is correct, this should fix it. Regardless, this does fix a bug that was in the code.
  * If the king dies right as another window is starting, right while the new window is starting to ProposeCommandline to the monarch, the monarch could die. If it does, the new window just explodes too. Not what you want.

Vaguely tested the second bug manually, by setting breakpoints in the monarch, starting a defterm, then exiting the monarch while the handoff was in process. That now creates a new window, so that's at least something. `RemotingTests::TestProposeCommandlineWithDeadMonarch` was the closest I could get to testing that.

The first bug only got an eye check. Not sure how to repro, but I figured yeet and hopefully we get it.

* [x] Closes #12624

(cherry picked from commit f507d9f491)
2022-03-11 13:53:49 -06:00
Dustin L. Howett
f553ac4657 Revert "Make sure Terminal Stable shows up default on 22544+" (#12664)
This reverts commit 457738e388.

(cherry picked from commit 814386f2c3)
Signed-off-by: Dustin Howett <duhowett@microsoft.com>
2022-03-10 17:31:33 -06:00
Dustin Howett
33659c8f12 Fix a build break in 19cd7c308 2022-03-10 17:05:07 -06:00
Mike Griese
addb3a3048 Add some disclaimer text to the schemes page (#12663)
People get confused about this. This should help. It doesn't really fix it, but it should help.

* [x] Does enough for #9775 to get it out of 1.14
* [x] I work here
* [x] Screenshot below.

![image](https://user-images.githubusercontent.com/18356694/157732913-86f0af51-8c37-4827-9d21-5775d0bfdeb7.png)

* [ ] todo: Discuss the text here. @cinnamon-msft this sound good?
2022-03-10 17:01:37 -06:00
Mike Griese
208dccd1b6 Make the Scrollbar 16dips again (#12608)
BODGY: Controlsv2 changed the size of the scrollbars from 16dips to
12dips. This is harder for folks to hit with the mouse, and isn't
consistent with the rest of the scrollbars on the platform (as much
as they can be).

To work around this, we have to entirely copy the template for the
ScrollBar into our XAML file. We're then also re-defining
ScrollBarSize here to 16, so that the new template will pick up on
the new value.

This is kinda a pain, and we have to be careful to be sure to ingest
an updated version of the template any time we update MUX. The
latest Controlsv2 version of the template can be found at:
https://github.com/microsoft/microsoft-ui-xaml/blob/main/dev/CommonStyles/ScrollBar_themeresources.xaml#L218

We're also planning on making this adjustable in the future
(GH#9218), where we might need this anyways.

##### after, before:
![image](https://user-images.githubusercontent.com/18356694/156254464-1a9080f6-51ce-4619-b002-2a3c607cdf5f.png)

##### after overlayed on top of before
![image](https://user-images.githubusercontent.com/18356694/156254546-fccc3cee-12a3-4e1a-8fd7-7470f1ec93ad.png)

##### comparison
![image](https://user-images.githubusercontent.com/18356694/156257934-ec4ac840-c8ca-4fca-a848-08a32b1c55c3.png)

* reported originally in #12395
* upstream: https://github.com/microsoft/microsoft-ui-xaml/issues/6684
* closes an element of #12400
2022-03-10 16:38:42 -06:00
Mike Griese
e967fd42cf Update the tab colors some more (#12635)
Again, to reflect continuing discussion with the WinUI team. A doc may have been misread - these are the colors they're proposing, which are generally a lot better.

See also: #12400, #12356, #12398

![image](https://user-images.githubusercontent.com/18356694/157041174-c0eb2140-3b49-4494-8746-b3a12f396fe6.png)
2022-03-10 16:38:28 -06:00
Mike Griese
cfc454ab22 Fix showing a dialog multiple times (#12625)
After the dialog is displayed, always clear it out. If we don't, we won't be able to display another!

* regressed in #12517.
* [x] Fixes #12622.
2022-03-10 16:38:13 -06:00
PankajBhojwani
f94da4f782 No longer load content dialogs when there is already one being shown (#12517)
Somehow, the controls v2 update caused an issue where if you as much as _load_ a content dialog when there's already one open, we get holes in the terminal window (#12447)

This commit introduces logic to `TerminalPage` to check whether there is a content dialog open before we try to load another one.

* [x] Closes #12447
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

Can no longer repro #12447
2022-03-10 16:37:51 -06:00
Carlos Zamora
4a73d470fc Stop making settings.json backups (#12652)
## Summary of the Pull Request
This makes it so that the settings.json backups are no longer created when the user saves their settings via the Settings UI.

Closes #11703

(cherry picked from commit 91f5648b5e)
2022-03-10 12:46:05 -06:00
Leonard Hecker
1a1d856c02 Replace Summon with Show/Hide for improved i18n (#12603)
"Summon" was translated as a synonym for "citation" in Spanish instead
of treating it as a RPG-related word. "Show/Hide" will hopefully
allow an improved automatic translation in the future.

Closes #10691

(cherry picked from commit f217f6dc33)
2022-03-10 12:46:05 -06:00
Ian O'Neill
19cd7c3085 Fix RTF generation for Unicode characters (#12586)
## Summary of the Pull Request
Fixes RTF generation for text with Unicode characters.

## PR Checklist
* [x] Closes #12379
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
Added some unit tests.

Ran the following in PowerShell and copied the emitted text into WordPad.
```pwsh
echo "This is some Ascii \ {}`nLow code units: á é í ó ú `u{2b81} `u{2b82}`nHigh code units: `u{a7b5} `u{a7b7}`nSurrogates: `u{1f366} `u{1f47e} `u{1f440}"
```

(cherry picked from commit 00113e3e48)
2022-03-10 12:45:38 -06:00
Mike Griese
9f0cf172f8 forgot to commit this 2022-03-04 06:24:06 -06:00
Mike Griese
cf26d2700b Update light theme tab background for greater contrast. (#12529)
Changes the tab view BG to `#e8e8e8`, as discussed in mail thread.

Closes #12398
2022-03-03 15:43:39 -06:00
Mike Griese
abdfbd5da0 Manually set the colors of the TabViewBackground (#12460)
This has been a saga.

Basically, any resources in `App.xaml` aren't going to be able to reference other theme-aware resources. We can't change the theme of the app at runtime, only elements within the app. So we can't use `ApplicationPageBackgroundThemeBrush` in app.xaml, because it will ALWAYS be evaluated as the OS theme version of that brush.

* regressed in #12326
* See also #10864
* #3917 CANNOT be fixed in the same way. We're lucky here that the TabView uses a `{ThemeResource TabViewBackground}` in markup to set the bg. We're not similarly lucky with the Pane one. 
* [x] closes #12356
* [x] Tested manually. You can confirm, my eyes are bleeding from the OS-wide light mode
2022-03-03 15:43:30 -06:00
Mike Griese
9e978b5fda Updates all our icons to use Segoe Fluent (#12469)
* use `FontFamily="{ThemeResource SymbolThemeFontFamily}"` where possible, in XAML
* use `FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" }` in codebehind

Basically just a simple string replace.

* [x] This was a bullet point in #11353
* [x] Confirmed manually on my win10 PC
* see also #12438

Actually, this is the last bullet in #11353, so I'm gonna say closes #11353. 

Screenshots below.
2022-03-03 15:35:29 -06:00
Mike Griese
e3a42b195e Enable Segoe Variable (#12462)
By adding another entry to our `maxversiontested`s.

Screenshots in https://github.com/microsoft/terminal/issues/12452#issuecomment-1035356054

* [x] Closes #12452 
* [x] I work here
* [x] Docs are fine
* [x] Tests are fine
2022-03-03 15:35:27 -06:00
PankajBhojwani
482fb68da9 Fix the add/delete unfocused appearance buttons (#12451)
## Summary of the Pull Request
The add/delete unfocused appearance buttons now have text on them and are closed to the `Unfocused appearance` header

## References
#11353 

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
<img width="548" alt="add" src="https://user-images.githubusercontent.com/26824113/153463971-de14a68b-5ed9-4768-80f8-2a5a5a21bc9f.png">
<img width="557" alt="delete" src="https://user-images.githubusercontent.com/26824113/153463993-9a7413d4-d895-4813-a6ff-1b157f1e72f4.png">
2022-03-03 15:35:26 -06:00
PankajBhojwani
489d85689b Fix focus box around color schemes combo box (#12439)
The focus box around the color schemes combo box was getting cut off, this change adds a small margin to the stackpanel to allow space for the focus box

## PR Checklist
* [x] Closes #12328
2022-03-03 15:35:26 -06:00
Mike Griese
fa410199af Properly fall back to Segoe MDL2 for our icons on Win10 (#12438)
Segoe Fluent isn't available on Windows 10, and doesn't stealthily ship with WinUI. So if we manually set the font family to `"Segoe Fluent Icons"`, then that will just display boxes in Win10.

This instead uses the resource `"{ThemeResource SymbolThemeFontFamily}"` which will gracefully fall back on Win10.

See:
* https://github.com/microsoft/microsoft-ui-xaml/issues/3745, which inspired this solution.

Guess what! The backgound image icons were also manually specifying this font, so they had to get updated too. I couldn't find any other `Segoe Fluent` references in the code.

* [x] Closes #12350
* [x] Checked Windows 11 locally
* [x] Checked Win10 (screenshots incoming from other machine)
2022-03-03 15:35:26 -06:00
PankajBhojwani
53cb56c0e9 Fix browse buttons getting cut off when the window is too narrow (#12435)
With the recent change to allow text boxes to be bigger, the `Browse` button that some of them have was getting cut off when the window was too narrow. This change puts the `Browse` button below the text box instead of next to it to prevent this issue.

## PR Checklist
* [x] Closes #12335
2022-03-03 15:35:25 -06:00
PankajBhojwani
3908bd3b83 Fix toggle switches needing a negative margin (#12381)
## Summary of the Pull Request
Reducing the `MinWidth` of a toggle switch means it no longer needs a negative margin to align it correctly

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
Setting a different language no longer causes the toggle switch to fall out of the expander
2022-03-03 15:32:28 -06:00
PankajBhojwani
4628e56723 Fix invoking the rightmost breadcrumb bringing you back to Profiles_Base (#12376)
## Summary of the Pull Request
We no longer do anything when the rightmost breadcrumb is invoked

## PR Checklist
* [x] Closes #12325 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
Tested manually, cannot repro #12325 anymore
2022-03-03 15:32:22 -06:00
PankajBhojwani
bc53333170 Fix disclaimer text not centralizing when maximized (#12374)
## Summary of the Pull Request
Fix the disclaimer text boxes in `Rendering` and `Defaults`not centralizing along with the expanders when the window is maximized

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
<img width="1128" alt="defaults" src="https://user-images.githubusercontent.com/26824113/152584084-a999cb29-73bc-4970-889a-f95ea64c1b4c.png">
<img width="1128" alt="rendering" src="https://user-images.githubusercontent.com/26824113/152584099-a54519da-7bca-4ebe-b487-b68ac5cf1a37.png">
2022-03-03 15:32:16 -06:00
Carlos Zamora
c0ae683738 Localize and polish Profile page navigators (#12321)
## Summary of the Pull Request
Adds some polish around the navigators in the profile page (i.e. "appearance" and "advanced" button) by doing the following:
- use the localized resources for the pivot on the navigators
- simplify the navigators to be buttons instead of toggle buttons

Doing so has Narrator identify these as buttons rather than toggle buttons. So now Narrator won't say that the button is "off", which just makes more sense.

## Validation Steps Performed
 Narrator says "Advanced button" or "Appearance button" on the navigator
 The navigators look the same as before
2022-03-03 15:32:12 -06:00
PankajBhojwani
38eb777112 Fix more SUI and Rejuvenated UI issues (#12326)
- The add new profile page now uses a dropdown rather than radio buttons
- Subheaders, breadcrumb bar, buttons etc are now all centralized when the window is maximized (so they all align with the expanders now)
- We no longer override the titlebar colors and instead use the xaml defaults (these still aren't great but at least we will get the fix automatically when it happens upstream)
- Breadcrumb bar no longer has a negative margin, so there's no weird overlap that happens when the window becomes small
- The number boxes for launch size and font size now use the `Inline` placement mode rather than compact, allowing modification to the number with fewer clicks
- Textboxes now have a greater max width so they can occupy more space in the expander if needed
2022-03-03 15:32:06 -06:00
PankajBhojwani
511ed89274 Fix a number of small issues with the SUI (#12287)
## Summary of the Pull Request
Fix various things from the recent SUI changes

- The Appearance/Advanced toggle buttons now have a max width
- We don't need `Profiles.cpp` anymore
- The `Elevate` setting is now back in the SUI
- There is no longer an alignment difference between non-expander settings and expander settings
- Expander settings no longer require hitting `Tab` twice to get to them

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here
2022-03-03 15:32:00 -06:00
Mike Griese
2ee347f882 This should have been in the parent commit 2022-03-03 15:26:02 -06:00
PankajBhojwani
c8c7d4b558 Add a BreadcrumbBar to the SUI (#12144)
**Note: This PR targets #11720**

Replaces our old pivot-style settings UI with a breadcrumb bar style, as per the windows 11 style guidelines. This required splitting `Profiles.xaml` into 3 separate files, `Profiles_Base.xaml` for general settings, `Profiles_Appearance.xaml` for appearance settings, `Profiles_Advanced.xaml` for advanced settings

The header in the navigation view is now a [BreadcrumbBar](https://docs.microsoft.com/en-us/windows/apps/design/controls/breadcrumbbar), which can be used to navigate back to `Profiles_Base` after moving into the advanced or appearance page (see GIF below)

<!-- Please review the items on the PR checklist before submitting-->
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

![breadcrumb](https://user-images.githubusercontent.com/26824113/150410517-2232811e-4f5b-4732-9a0d-569cc94093b3.gif)
2022-03-03 15:07:01 -06:00
Michael Niksa
5ff1659c19 Fix release YML paths for VPACK for Win10/11 split (#12621) 2022-03-03 13:04:51 -08:00
Carlos Zamora
57ec119ebe Fix broken reset button on some profile settings (#12275)
This fixes a bug where several settings would not show the reset button. The root cause of this issue is two fold:
1. Hooking up `CurrentXXX`
   - `GETSET_BINDABLE_ENUM_SETTING` was hooked up to the **settings** model profile object instead of the **view** model profile object. Since the settings model has no `PropertyChanged` system, any changes were directly being applied to the setting, but not notifying the view model (and thus, the view, by extension) to update themselves.
   - This fix required me to slightly modify the macro. Rather than using two parameters (object and function name), I used one parameter (path to getter/setter).
2. Responding to the `PropertyChanged` notifications
   - Now that we're actually dispatching the `PropertyChanged` notifications, we need to actually respond to them. This behavior was defined in `Profiles::OnNavigatedTo()` in the `PropertyChanged()` handler. Funny enough, that code was still there, it just didn't do anything because it was trying to notify that `Profiles::CurrentXXX` changed. This is invalid because `CurrentXXX` got moved to `ProfileViewModel`.
   - The fix here was pretty easy. Just move the property changed handler to `ProfileViewModel`'s `PropertyChanged` handler that is defined in the ctor.

Bug introduced in #11877

 Profile termination behavior
 Bell notification style
 Text antialiasing
 Scrollbar visibility
2022-03-03 15:04:37 -06:00
PankajBhojwani
49b79787b0 Update our SUI to follow win 11 guidelines (#11720)
Updates our SUI to follow the windows 11 style guidelines. Includes updating our setting containers to follow the 'expander' style.

* [x] Closes #10631
* [x] Closes #9978
* [x] Closes #9595
* [x] Closes #11231
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here
2022-03-03 14:59:58 -06:00
PankajBhojwani
9b4ee32f8c Switch WinUI to the Windows 11 styles (#12241) 2022-03-03 14:58:02 -06:00
Carlos Zamora
fe46f70cf1 Apply MVVM for profiles in SUI (#11877)
Cleans up `ProfileViewModel`, `Profiles`, and `ProfilePageNavigationState` to move all of the view model responsibilities over to `ProfileViewModel`. We don't actually store the `ProfilePageNavigationState` anymore. We only use it as a way to transfer information to the new page.

- I pulled out `ProfileViewModel` into its own file to keep things cleaner. It was getting pretty big.
- The font lists are now stored in a static location in `ProfileViewModel`, which means that we can reuse the same list between pages.
- the profile pivot was also moved to the `ProfileViewModel` and stored as a static value.

 pivot behavior is the same
 font list is still populated
2022-03-03 14:57:24 -06:00
Leonard Hecker
4c5bd69d51 Fix OpenConsoleProxy for Debug builds (#11632) 2022-03-03 09:39:25 -08:00
Ian O'Neill
b005ffcf07 Don't crash trying to parse a command line that's a directory (#12538)
## Summary of the Pull Request
Prevents a crash that could occur when invoking `wt C:\`

## PR Checklist
* [x] Closes #12535
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments
Updates `CascadiaSettings::NormalizeCommandLine()` to check that there are a suitable number of command line arguments to be concatenated together, to prevent accessing an array index in `argv` that doesn't exist.

Also prevents a test flake that could occur in `TerminalSettingsTests::CommandLineToArgvW()`, due to generating an empty command line argument.

## Validation Steps Performed
Added a test, and checked that invoking each of the command lines below behaved as expected:
```
wtd C:\ # Window pops up with [error 2147942405 (0x80070005) when launching `C:\']
wtd C:\Program Files # Window pops up with [error 2147942402 (0x80070002) when launching `C:\Program Files']
wtd cmd # cmd profile pops up
wtd C:\Program Files\Powershell\7\pwsh -WorkingDirectory C:\ # PowerShell profile pops up in C:\
wtd "C:\Program Files\Powershell\7\pwsh" -WorkingDirectory C:\ # PowerShell profile pops up in C:\
wtd . # Window pops up with [error 2147942405 (0x80070005) when launching `.']
```
2022-03-02 15:01:37 -08:00
Dustin L. Howett
016320e987 Protect the command palette against being paged with no items (#12528)
Fixes two crashes amounting to 14% of our crash burden in Simulated
Selfhost. I can't reproduce this organically, but I was able to do so by
forcing the command palette to be empty.
2022-03-02 15:01:19 -08:00
Mike Griese
0ac8e88a3a Fix a crash setting the hotkey during teardown (#12580)
From MSFT:36797001. Okay so this is only .22% of our crashes, but every little bit helps, right?

Turns out this is also hitting in:
* MSFT:35726322
* MSFT:34662459

and together they're a fairly hot bug.

There's a large class of bugs where we might get a callback to one of our event handlers when we call `app.Close()` in the `AppHost` dtor. This PR adds manual revokers to these events, and makes sure to revoke them BEFORE nulling out the `_window`. That will prevent callbacks during the rest of the dtor, when the `_window` is null.
2022-03-02 15:00:30 -08:00
Dustin Howett
8a753e3a47 fix: set the MaxVersionTested for 1.12 to 22000 2022-02-24 18:43:02 -06:00
Dustin L. Howett
4d05c7b0d8 build: ship a Win11 build of Terminal that's <=half the size (#12560)
Four (4) squashed changes, with messages preserved.

Right now, symbol publication happens every time we produce a final
bundle. In the future, we may be producing multiple bundles from the
same pipeline run, and we need to make sure we only do *one* symbol
publication to MSDL.

When we do that, it will be advantageous for us to have just one phase
that source-indexes and publishes all of the symbols.

This removes the trick we pulled in #5661 and saves us ~550kb per arch.

Some of our dependencies still depend on the "app" versions of the
runtime libraries, so we are going to continue shipping the forwarders
in our package. Build rules have been updated to remove the non-Desktop
VCLibs dependency to slim down our package graph.

This is not a problem on Windows 11 -- it looks like it's shipped inbox.

**BREAKING CHANGE**: When launched unpackaged, Terminal now requires the
vcruntime redist to be installed.

common.openconsole.props is a pretty good place to stash the XAML
version since it is included in every project (including the WAP
project (unlike the C++ build props!)).

I've gone ahead and added a "double dependency" on multiple XAML
versions. We'll toggle them with a build flag.

This required some changes in how we download artifacts to make sure
that we could control which version of Windows we were processing in any
individual step.

We're also going to patch the package manifest on the Windows 11 version
so the store targets it more specifically.

On top of the prior three steps, this lets us ship a Windows 11
package that costs only ~15MB on disk. The Windows 10 version, for
comparison, is about 40.

(cherry picked from commit 53a454fbd3)
2022-02-24 18:14:08 -06:00
Mike Griese
0327c3aede Fix a crash in DefTerm+Monarch launch (subset of #12205)
(cherry picked from commit dd213a5c18)
2022-02-18 12:50:23 -06:00
PankajBhojwani
4e6431cac0 Fix font axes/features not working on DPI change (#12492)
When the dpi is changed, call `updateFont()` instead of `TriggerFontChange`, this
means that we continue to use the existing font features/axes

Closes #11287

(cherry picked from commit 3b4679431d)
2022-02-16 11:56:22 -06:00
Dustin L. Howett
20a1048d49 Copy localized strings from ContextMenu into the resource root (#12491)
We chose to use the "ContextMenu" resource compartment when we
changed the package name to Terminal in #12264 because it was more
broadly localized than the rest of the application.

It appears as though some platform features have trouble with the
"more qualified" resource paths that #12264 required.

To fix this, we will:

1. Copy all of the ContextMenu localizations into CascadiaPackage's
   resource root
2. Switch all manifest resource paths to use resources from the package
   root.

Regressed in #12264
Closes #12384
Closes #12406 (tracked in microsoft/powertoys#16118)

(cherry picked from commit 9501b23ad1)
2022-02-16 11:56:22 -06:00
Leonard Hecker
0892a13793 Fix off-by-one bug in NormalizeCommandLine (#12484)
#12348 introduced an off-by-one bug. While the `NormalizeCommandLine` loop
should exit early when there aren't at least _two_ arguments to be joined,
the final argument-append needs to happen even if just _one_ argument exists.

This commit fixes the issue and introduces changes to additionally monitor
the early loop exit, as well as the call to `ExpandEnvironmentStringsW`.

## PR Checklist
* [x] Closes #12461
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* All `TerminalSettingsTests` tests pass 

(cherry picked from commit e06e1314a8)
2022-02-16 11:56:22 -06:00
Michael Niksa
6419ac1d0c Source index the public symbols too (#12450)
Now that we've figured out how to publish the public symbols to the official Microsoft download server... we may as well embed the source code linking information inside of them given that it's right here on GitHub. This attempts to run our existing source linking scripts against the public copy of the symbols.

## PR Checklist
* [x] Closes #12443
* [x] I work here
* [x] Tested manually

## Validation Steps Performed
* [x] Build with it: https://dev.azure.com/microsoft/Dart/_build/results?buildId=44930661&view=logs&j=8f802011-b567-5b81-5fa6-bce316c020ce
* [x] Point the debugger at them and see if it can find the sources
* [x] Maybe also look at them in a hex editor or whatnot and validate I can see the source paths pointing at GitHub

(cherry picked from commit 8b9066962d)
2022-02-16 11:56:21 -06:00
Mike Griese
6c7b769bb5 Update the cmdpal narrator message to include the number of results. (#12429)
Updates this narrator announcement message to include the number of results it found. There are two versions:
* one for a singular result
* one for multiple results.

which should help with loc.

We're trying to get this in with the loc hotfix, so 👀 please

* [x] will take care of the last bit of #7907

verified with narrator locally.

(cherry picked from commit 9ea0c93435)
2022-02-16 11:56:21 -06:00
Michael Niksa
b9566a1f3e Automate packaged submission into Windows (#12449)
We're now building a fully provenance, compliance, and security
validated package (vpack) through our Release pipeline. This attaches
the last phase which automates the submission into the Windows product.
It will also automatically trace back the source, commit SHA, and build
to the submission here from the Windows side.

* [x] Automates a manual activity I performed a few times recently
* [x] I work here
* [x] Ran a test of it against `release-1.12` and it worked

(cherry picked from commit 10c963a7db)
2022-02-16 11:56:17 -06:00
Mike Griese
a84ba7364e Don't ever allow ~ as a startingDirectory (#12437)
Basically, some WSL distros ship fragments that replace the `commandline` with the executable for their distro (`ubuntu.exe`, etc.). We didn't expect that when we changed the `startingDirectory` for them all to `~`.

Unfortunately, `~` is really never a valid path for a process on windows, so those distros would now fail with

```
[error 2147942667 (0x8007010b) when launching `ubuntu1804.exe']
Could not access starting directory "~"
```

If we find that we were unable to mangle `~` into the user's WSL `commandline`, then we will re-evaluate that `startingDirectory` as `%USERPROFILE%`, which is at least something sensible, if albeit not what they wanted.

* regressed in #12315
* [x] Closes #12353
* [x] Tested with a (`ubuntu1804.exe`, `~`) profile - launched successfully, where 1.13 in market fails.
* [x] added tests
2022-02-08 18:51:25 -06:00
Carlos Zamora
26a001fa6a Validate cursor position in UIA UTR ctor (#12436)
This adds some validation in the `UiaTextRange` ctor for the cursor position.

#8730 was caused by creating a `UiaTextRange` at the cursor position when it was in a delayed state (meaning it's purposefully hanging off of the right edge of the buffer). Normally, `Cursor` maintains a flag to keep track of when that occurs, but Windows Terminal isn't maintaining that properly in `Terminal::WriteBuffer`.

The _correct_ approach would be to fix `WriteBuffer` then leverage that flag for validation in `UiaTextRange`. However, messing with `WriteBuffer` is a little too risky for our comfort right now. So we'll do the second half of that by checking if the cursor position is valid. Since the cursor is really only expected to be out of bounds when it's in that delayed state, we get the same result (just maybe a tad slower than simply checking a flag).

Closes #8730 

Filed #12440 to track changes in `Terminal::_WriteBuffer` for delayed EOL wrap.

## Validation Steps Performed
While using magnifier, input/delete wrapped text in input buffer.
2022-02-08 18:50:45 -06:00
Dustin L. Howett
2f18fc1a25 Publish the symbols from our MSIX bundle to the public server (#12441)
Closes #12203
2022-02-08 18:50:45 -06:00
Mike Griese
3e5e0dbc1c Fix a potential crash when setting up the jumplist (#12430)
I have no idea how this is even possible to hit. If this is able to be null, then we failed to load the settings in such a catastrophic way that nothing should work. However, OP's Terminal seemed to have already loaded the settings. By all accounts, doesn't make sense.

Regardless, the code here would crash if this ever is null, so we may as well catch it.

* [x] Closes #12360
* [ ] No way to verify this since it isn't even reproable on OPs machine, but it does have a lot of hits for that failure bucket (!!!)
2022-02-08 18:50:45 -06:00
Leonard Hecker
1da3c7f080 Fix profile matching for paths containing unquoted whitespace (#12348)
The previous code had two bugs for:
* paths with more than 1 whitespace
  The code joins the argv array by replacing null-word terminators with
  whitespace. Unfortunately it always referred to the separator between
  `argv[0]` and `argv[1]` for this instead of continuing to join
  those between 1 and 2, etc.
* paths sharing a common prefix with another directory
  `SearchPathW` returns paths that aren't necessarily paths to files.
  A call to `GetFileAttributesW` was added, ensuring we only resolve file paths.

* [x] Closes #12345
* [x] I work here
* [ ] Tests added/passed

* Paths with more than 1 whitespace resolve correctly 
* Paths with neighboring directories sharing a common prefix resolve correctly 
* Tests added 
2022-02-08 18:50:43 -06:00
Michael Niksa
4eaeaad3ac Hardcode the language list for the package manifest and settings dropdown (#12375)
The `x-generate` statement seems to have fallen apart somewhere and is no longer generating the valid list of languages for display. This hardcodes the list into the manifest to restore it, which is a valid option per the documentation.

We also hardcode the limited subset of languages into the Settings application because the main application supports fewer languages than we have been translated into for the shell extensions for Windows Explorer and Start Menu integration.

## PR Checklist
* [x] Closes #12351
* [x] I work here.
* [x] Manual tests below

## Validation Steps Performed
- [x] Clean built locally with `msbuild.exe openconsole.sln /p:Configuration=Release /p:Platform=x64 /p:WindowsTerminalBranding=Release /t:Terminal\CascadiaPackage /m /bl:log4.binlog` and checked that the `appxmanifest.xml` that popped out the other side contained the same languages that it used to contain.
- [x] Built in the release pipeline
- [x] Installed release and preview branded packages. Changed my machine language to Polish (pl-PL) which is not one of the fully localized languages, but is one of the limited ones. Checked the start menu and right-click menus and saw Polish text for Terminal and Terminal Preview. Checked the Settings page in our app and saw only the limited 14 language list for the application itself.
2022-02-08 18:49:59 -06:00
Dustin L. Howett
25e67fee59 appx: Use a different resource for the Properties DisplayName (#12337)
We have to do this so that the store sees us as one thing ("Windows
Terminal") and the Start menu sees us as another ("Terminal").

The store will reject our package if the value we use for "DisplayName"
here doesn't match the store's "reserved names".

This value is *not used* by the start menu.

(cherry picked from commit e064c15675)
2022-02-02 21:00:03 -06:00
Carlos Zamora
c4826198dc Update accessible names for 'add profile' page buttons (#12324)
## Summary of the Pull Request
When using a screen reader, the buttons on the "add a new profile" page were being read weirdly:
- "New empty profile" button read as "create new button button"
- "duplicate" button read as "duplicate button button"

It's generally standard to read out the text inside the button, so I did just that by reusing the existing localized resources. This also removes the redundant "button" that is said by the screen reader.

I also removed the unused `AutomationId` and unnecessary `Button.Content` tags.

#11156 can be closed upon validation by the accessibility team.

## Validation Steps Performed
 navigate to both buttons using Narrator; make sure it sounds right

(cherry picked from commit 24c5f7bba4)
2022-02-02 15:45:13 -06:00
Mike Griese
4b9dc5ba84 Research how often folks disable the KB warning (#12322)
(cherry picked from commit bf32f45616)
2022-02-02 13:00:30 -06:00
Dustin L. Howett
093ab06272 Make sure Terminal Stable shows up as default on 22544+ (#12320)
Since we turned this feature on in windows, and it relies on _lying
about the contents of the registry_, Terminal needs to be in on the
joke.

This will need to be reverted and serviced if we choose not to ship like
this.

Fixes #12308

(cherry picked from commit 457738e388)
2022-02-02 13:00:30 -06:00
Dustin L. Howett
d3d68ac874 Set the default WSL starting directory to ~ (#12315)
The update that enables this on 20H1+, [KB5007253], went out in November
2021.

[KB5007253]: https://support.microsoft.com/en-us/topic/november-22-2021-kb5007253-os-builds-19041-1387-19042-1387-19043-1387-and-19044-1387-preview-d1847be9-46c1-49fc-bf56-1d469fc1b3af

(cherry picked from commit 70d8b2a2ef)
2022-02-02 13:00:30 -06:00
Dustin Howett
a84d988473 Remove a test that doesn't compile without /permissive- 2022-02-01 09:57:10 -06:00
Mike Griese
9ec2667ae3 This actually fixes the FI. I obviously forgot to build the tests.
(cherry picked from commit a2e93284ee)
2022-01-31 19:41:37 -06:00
Mike Griese
89f9a55258 Uh oh someone broke main on an FI
Fixes FI bugs introduced in 33c2cd458a

(cherry picked from commit d4ebcc27eb)
2022-01-31 19:39:20 -06:00
Michael Niksa
7438669930 Add PGOBuildMode to PGD merge step (#12306)
I added a condition to exclude some of the NuGet PGO stuff when there was no build mode, but appear to not have propagated any of it in the PGD merge job. This sets it to Optimize here so it'll go through.

## PR Checklist
* [x] Closes #12300
* [x] I work here.
* [x] It blends.

## Validation Steps Performed
* [x] Ran the PGO Instrument Phase
* [x] Ran the PGO Optimize Phase

(cherry picked from commit 469202f462)
2022-01-31 19:14:02 -06:00
Mike Griese
e103a7364b Make the SearchBox announce if it found results or not (#12301)
Basically, this is the same as #12266, but for the `SearchBoxControl`. Trickily, the ControlCore is the one that knows if there were search results, but the TermControl has to be the one to announce it.

* [x] Will take care of #11973 once a11y team confirms
* [x] Tested manually with Narrator
* [x] Resolves a part of #6319, which I'm repurposing just to displaying the number of results in general.
* See also #3920

(cherry picked from commit fbe0416305)
2022-01-31 18:52:01 -06:00
Mike Griese
5664cf84e5 Add a11y names to more controls (#12299)
This adds names to more of our focusable elements. This should be the rest of them that I missed in #11364

* #9990: a11y megathread
* #11155: original version of this

* [x] Should take care of #11996 once confirmed
* [x] I work here

Used Accessibility Insights to verify.

There is one other weird bit. All the expanders that have content below the expander (not inline), show up as focusable, but don't have names. Even when I add names to them. I believe this is due to https://github.com/microsoft/microsoft-ui-xaml/issues/5820, which is fixed in https://github.com/microsoft/microsoft-ui-xaml/pull/6032, in https://github.com/microsoft/microsoft-ui-xaml/releases/tag/v2.8.0-prerelease.220118001. Unfortunately, we're on a 2.7 prerelease, so we don't have that fix yet. I may see how painful moving to that is, because we're gonna get another a11y ping as soon as 1.13 ships.

I pre-emptively added names to these guys in f7ba158dc, so that the new MUX should just fix this without any thinking on our part.

(cherry picked from commit cf4d47c54d)
2022-01-31 18:48:57 -06:00
Mike Griese
b53a902b55 Change where the NotificationIcon looks up our resources (#12282)
I didn't have the tray icon enabled before I suppose, so this never got hit? Anyhow, we need to change where we look for the AppName. Otherwise we crash on launch 😨

* [x] fixes `main`
* [x] I work here
* regressed in #12264
* [x] Tested by: actually running the Terminal with this, it launched

(cherry picked from commit 7150fd8f97)
2022-01-31 11:02:19 -06:00
Carlos Zamora
99dd8549f3 Fix SizeOfSet and PositionInSet for 'Open JSON File' nav item (#12286)
## Summary of the Pull Request
According to https://github.com/microsoft/microsoft-ui-xaml/issues/1971, `PaneFooter` does not set the `SizeOfSet` or `PositionInSet` properties. However, `FooterMenuItems` does and works for our scenario. So we just replaced `PaneFooter` with `FooterMenuItems`.

Will handle #11154 upon verification from the accessibility team.

## Validation Steps Performed
 Verified using Accessibility Insights
 "Open Json File" button can still be invoked and keyboard navigated to as expected

(cherry picked from commit 2861b41fd0)
2022-01-31 10:59:03 -06:00
Dustin L. Howett
0837b186cb Move to the 21H1 Helix pool (#12285)
The 19H1 pool is being decommissioned.

(cherry picked from commit eb7559733d)
2022-01-31 10:59:03 -06:00
Mike Griese
38b4a858c9 Rename "Windows Terminal" -> "Terminal" (#12264)
This should be most of the surfaces that we really care about for displaying "Windows Terminal". There's a pile of other references in code, but I couldn't find any other resources that mention it.

I left a lot of the references to Windows Terminal throughout. Seemed like it was fine to keep calling it that in most places, just these localized strings that are going to be displayed in the Shell that should be changed.

Rough compare:
![image](https://user-images.githubusercontent.com/18356694/151248506-edf9a6ab-d93f-438f-8755-cdf6ae643736.png)

The strings were also moved to the Context Menu resources file, because that's localized into more languages.

@DHowett we may want to spin a full build to make sure this works and I didn't miss anything

* [x] Closes #12091

(cherry picked from commit a66a1c0cf5)
2022-01-31 10:58:13 -06:00
Carlos Zamora
a03fde9cac [Command Palette] Announce if suggestions were found to screen readers (#12266)
## Summary of the Pull Request
Expands on #9582. If the command palette finds results, the screen reader says "Suggestions available".

Makes the scenario mentioned in #7907 work.

This is sufficient for various reasons:
1. According to the bug report, saying that suggestions are available is sufficient
> Screen reader should provide the results info on searching commands like 10 results found or suggestions available when there are any search results (Source: #7907)

2. This is common practice. Settings app and XAML Controls Gallery do this for their search box.

Also, the user should be able to know how many results were found by tabbing/selecting a result item. When this is done, the screen reader will use `SizeOfSet` and `PositionInSet` to announce how many results were found and which one we're currently on.

## Validation Steps Performed
Verified this behavior using Narrator.
Verified it matches the behavior of the Settings app and the XAML Controls Gallery.

(cherry picked from commit 1e47d7aca7)
2022-01-31 10:58:13 -06:00
Mike Griese
8baf3af5e1 Add a keyboard shortcut handler to the TabRowControl (#12260)
This makes the scenario mentioned in #8480 work. It's maybe not as holistic a solution as we'd like, but it definitely works.

Tested both with Narrator, and using the TabView scroll handles to get tab focus into the tab row manually

* [x] Closing the _active_ tab with <kbd>Ctrl+Shift+w</kbd> works (not the `TabViewItem` that has focus, but that's how Edgium works so that seems fine)
* [x] Opening a tab with <kbd>Ctrl+Shift+t</kbd> works
* [x] Opening the cmdpal with <kbd>Ctrl+Shift+p</kbd> works
* [x] Will take care of #8480 once we get the a11y team to validate
* [x] I work here

#### Notes:

None of

```xaml
PreviewKeyDown="_KeyDownHandler"
KeyDown="_KeyDownHandler"
KeyUp="_KeyDownHandler"
```

On the TerminalPage directly seem to fire when the focus is in the `TabViewItem` or the New Tab flyout. But they fire just fine when focus is in the `TermControl`. Interesting, because you'd think that the `TermControl` would have already handled the key...

(cherry picked from commit 6f69487829)
2022-01-31 10:58:13 -06:00
Carlos Zamora
adbf2fa7e2 Expose Defterm info to ComboBoxItem properly (#12259)
## Summary of the Pull Request
Makes `Model::DefaultTerminal` an `IStringable`, which presents it as a string, when possible. This enables text search for defterm's setting. This also enables screen readers to identify the combo box items by their text content (app name, author, and version) as opposed to being treated as an item containing more text. As a part of that, I cleaned up the UIA tree to treat the item's name as "\<name\>, \<author\>, \<version\>". This is consistent with how the Settings App presents installed apps in Apps > Installed apps.

#11251 will be resolved upon verification by the accessibility team.

## Validation Steps Performed
Verified using Narrator and Accessibility Insights.

(cherry picked from commit d89c241dac)
2022-01-31 10:58:13 -06:00
Michael Niksa
0655dfd354 Update PGO helpers to mitigate Y2K22 bug (#12262)
The PGO helpers NuGet had the Y2K22 bug. This receives and integrates the updated package in our project to restore NuGet functionality.

## PR Checklist
* [x] Closes #12261
* [x] I work here
* [x] If it builds it sits.

## Validation Steps Performed
* [x] Build new PGO instrument data with this pipeline update: https://dev.azure.com/microsoft/Dart/_build/results?buildId=44304850&view=results

(cherry picked from commit fe52368f9b)
2022-01-31 10:58:13 -06:00
Mike Griese
c4398bac5d Send an updated cursor position at the end of writing a run (#12210)
I can find the commit where this regressed tomorrow if needed. In #10685 we stopped emitting these notifications while we were deferring cursor drawing. We however forgot to send the notification at the end of the defer.

This likely has a small perf impact. We however do need these cursor position events for IMEs to be able to track the cursor position (and low key for #10821)

* [x] regressed in #10685
* [x] Closes #11170
* [x] I work here
* [x] Tests added

(cherry picked from commit 01fd7141ed)
2022-01-31 10:58:13 -06:00
James Holderness
0d1e4d3461 Make sure titles always sanitized before passing over conpty (#12211)
When title updates are forwarded from the host to the client terminal,
they're passed over conpty in an `OSC 0` sequence. If there are any
control characters embedded in that title text it's essential they be
filtered out, otherwise they are likely to be misinterpreted by the VT
parser on the other side. This PR fixes a case where that sanitization
step was missed for titles initialized at startup.

Originally the sanitization step was handled in `DoSrvSetConsoleTitleW`,
which catches title changes made via VT escape sequences, or through the
console API, but missed the title initialization at startup. I've now
moved that sanitization code into the `CONSOLE_INFORMATION::SetTitle`
method, which should cover all cases.

This sanitization is only meant to occur when in "pty mode", though,
which we were originally establishing with an `IsInVtIoMode` call.
However, `IsInVtIoMode` does not return the correct result when the
title is set at startup, since the VT I/O thread is not initialized at
that point. So I've instead had to change that to an `InConptyMode`
call, which determines the conpty state from the launch args.

## Validation Steps Performed

I've manually confirmed the test case described in issue #12206 is now
working correctly.

However, the change to using `InConptyMode` caused some of the unit
tests to fail, because there isn't a real conpty connection when
testing. Fortunately there are some `EnableConptyModeForTests` methods
used by the unit tests to fake the appearance of a conpty connection,
and I just needed to add some additional state in one of those methods
to trigger the correct `InConptyMode` response.

Closes #12206

(cherry picked from commit 3804f2672e)
2022-01-31 10:58:13 -06:00
Leon Liang
2c3bf1880d PR 6616045: Hand off to Windows Terminal Stable by default (!)
This commit also introduces a check that we are in an interactive
session before we perform handoff, so as to not break service accounts.

It also adds some tracing.

Merged PR 6882227: [Git2Git] Merged PR 6881763: Change to hardcoded system GUIDs to appease manifest validation

Manifest validation won't accept migration/initialization of HKCU-based registry keys anymore. The enforcement scripts says that they should be defined in code instead. So here it is: defined in code insteead.

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 67c720b628de4acefbc381891b7e7d29d387038e

Related work items: MSFT-37867666
2022-01-31 10:50:35 -06:00
Dustin L. Howett
42e5671a79 [build] Fix the release build after we removed WTU (#12188)
(cherry picked from commit 4e46c855e9)
2022-01-21 15:01:59 -06:00
Mike Griese
fffcb63877 Manually replace unqualified cmd, powershell paths for the default profiles (#12149)
In previous releases, we had the commandlines for the Command Prompt and PowerShell profiles unqualified, as `cmd.exe` and `powershell.exe`. This was bad - theoretically, that would have preferred the cmd that was in the CWD over the one in System32. Or, something could insert itself into the path, and you'd end up with a malicious `cmd.exe` before the real one.

In #11437, we made sure that the `userDefaults` are initiated with the fully qualified paths. However, that didn't fix the issue for folks who already had settings files.

In an effort to better prevent this kind of badness, if we see a profile _with a default profile guid_, AND the unqualified version of the path, then we'll stealth replace it with the fully qualified one.

* Related to #11437
* [x] fixes #12126
* [x] Tests added

(cherry picked from commit f1baa319fc)
2022-01-21 15:01:59 -06:00
Mike Griese
75745df774 Make sure to copy connectionType for the azure shell (#12147)
This was a simple oversight. No user profile ever has `connectionType` set, because why would they. So even for the Azure Shell, which needed this, the check would fail and we'd forget to duplicate the connectionType to the new profile.

* [x] I work here
* [x] Closes #12120
* [x] Tested manually

(cherry picked from commit eb83469874)
2022-01-21 15:01:59 -06:00
Mike Griese
d91b4ca899 Fix //wsl$ paths not working in MangleStartingDirectoryForWSL (#12102)
This PR does two things, which are best viewed as atomic commits:
* e64ae7d: Move the `MangleStartingDirectoryForWSL` to `types/utils`. It doesn't _really_ make sense in `types`, since it's only really being used in a single place in TerminalConnection. However, TerminalConnection doesn't have tests, and types does. So this commit move the function there, and adds tests from #9223 to the types tests.
* 42036c5: This actually fixes the bug in #11994. Unfortunately, `wsl --cd` will try to treat paths starting with `//wsl$` as a linux-relative path, when the user almost certainly wanted a windows-relative one. So we'll mangle that back into a path that looks like `\\wsl$\foo\bar`.
* [x] closes #11994
* [x] I work here
* [x] tests added 🎉

(cherry picked from commit b87b809fa0)
2022-01-21 15:01:55 -06:00
Michael Niksa
b512e7d5a4 Pass additional parameters when making PGO package (#12131)
(cherry picked from commit d0c4cf744c)
2022-01-21 15:00:46 -06:00
Mike Griese
6d86429522 Initialize cursorOn to match focus state (#12094)
I'm not 100% sure that this is the right solution, but it does seem to work well enough. This is unfortunately a classic heisenbug. It was already hard enough to repro originally, but attaching a debugger made it totally impossible to hit.

My theory is that it's possible for the GotFocus event to fire before the LayoutUpdated event does. If that were to occur, then we'd try to turn on the cursor timer before it exists, gracefully do nothing, then create the timer. In that case, we'd never get a subsequent message to start the blinking.

I tested that theory by just initializing the cursor blinker to our `_focused` state. In that case, if the control has already been focused at the time of the LayoutUpdated event, then we can init the cursor to the correct state. Testing that out, I couldn't once get this to repro, which makes me think this works. I've opened some 900 (<sup>hyperbole</sup>) tabs now, so I'm pretty confident I'd have seen it by now.

* Regressed in #10978
* [x] fixes #11411
* [x] I made sure I didn't regress #6586
* [x] I work here

(cherry picked from commit 55aea08d15)
2022-01-21 15:00:46 -06:00
Michael Niksa
d8170bcbb6 Remove deprecated Windows Terminal Universal project (#12119)
Remove deprecated Windows Terminal Universal project

* [x] Closes #12118
* [x] I work here

(cherry picked from commit 591b949b3c)
2022-01-21 15:00:44 -06:00
Dustin L. Howett
503e27e475 Move the context menu strings to a separate resw compartment (#12090)
This is so that they can be localized separately, and into more
languages.

References MSFT-33615189

(cherry picked from commit 63a3517871)
2022-01-21 15:00:24 -06:00
Davide Giacometti
b30137b94f Disable duplicate button without selected profile (#12096)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

- Settings > Add a new profile
- Disable "Duplicate" button until a profile is selected

![Duplicate](https://user-images.githubusercontent.com/25966642/148303450-a084cd5f-7f1c-4de3-86bd-602b9336649e.gif)

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Should take care of #12056, once we can get a build to the a11y team (MAINTAINER EDIT: we unfortunately can't just say "closes #foo" for issues like this one, we need another team to validate the following build.)
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

(cherry picked from commit a766798fb8)
2022-01-21 15:00:24 -06:00
Luan Vitor Simião Oliveira
c197ca5f5d fix ~ not work as startingDirectory for WSL (#12050)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
fix #11432
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #11432
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
compiled and verified that "\~"  ,  "/usr/bin"  ,  "~/.config" and "/" as stating directory didn't get relative path resolve
verified that '.' did

(cherry picked from commit c98ec15144)
2022-01-21 15:00:24 -06:00
Ian O'Neill
717d9b77c3 Ensure PowerShell Core profile commandline is quoted (#12086)
Ensures the PowerShell Core profile's commandline is quoted. This allows
the profile to work correctly if there are files in place on the machine
(e.g. one called `C:\Program`) that prevent `CreateProcess()` from
invoking the un-quoted commandline.

## Validation Steps Performed
Created a file called `C:\Program` and opened the PowerShell profile in
terminal.

Closes #11717

(cherry picked from commit 4930508b8c)
2022-01-21 15:00:24 -06:00
James Holderness
48cb5f0bfa Use the correct background color when copying to clipboard (#11991)
When copying content from the terminal to the clipboard (with
formatting), a default background color needs to be set to fill the
unused area of the pasted block. Prior to this PR, that color was not
correctly set, so the pasted content did not match what was seen on
screen.

Windows Terminal previously used the default background from the initial
color scheme, so it didn't take palette changes into account.
OpenConsole did use the active default color, but didn't take the
reverse screen mode into account, so could end up using the foreground
rather than the background color.

In both case I've changed the code to lookup the runtime colors in the
same way that renderer does, so they should now match what is seen on
screen.

I've manually confirmed that the background color is now correctly set
when copying from both Windows Terminal and OpenConsole.

Closes #11988

(cherry picked from commit b61b24ecd1)
2022-01-21 15:00:22 -06:00
PankajBhojwani
df2d9fc542 Revert delta E change for release 1.12 (#12163)
Co-authored-by: Pankaj Bhojwani <pabhojwa@microsoft.com>
2022-01-14 08:20:24 -08:00
Michael Niksa
789d22ef2b Enable Security and Compliance tasks in our Release pipeline (#11849)
Enables a series of tasks run against our release pipeline that validate the security and compliance status of our code in an automated fashion. These checks include:
- Component Governance - (we had this one, it was moved to here) - Inventories open-source components used in our build
- PREfast - C/C++ static analysis for common code errors and exploits
- Policheck - Searches source code, comments, and text for words that could be sensitive legally, culturally, or geopolitically
- Credscan - Looks for credentials left behind in the code/documents and build output files
- BinSkim - Searches for common vulnerabilities in binaries
- CheckCFlags - Validates that compile/link flags match the policies recommended by Windows engineering for inclusion into the OS product image
- CFGCheck/XFGCheck - Validates that the CFG and/or XFG settings were enabled at compile and link time to guard against control flow attacks.

We're also required to run the SBOM one, but that was done in a separate PR and we're still pending the detectors being updated.

- #11948 - Move from CFG to XFG once XFG task folks get back to me on it
- #11949 - Enable bug filing for SecComp tasks
- #11950 - Bulk process bugs filed by SecComp tasks
- #11947 - Validate SBOM when checkers come online

- [x] - Fixes #10735
- [x] - Fixes #908
- [x] - I work here
- [x] - If it fits, it sits.
2022-01-10 14:47:51 -08:00
Michael Niksa
db5ddccc17 Only look for PGO package if build mode targeted; add packages.config dependency to ease restoration (#11981)
Only look for PGO package if build mode targeted; add packages.config dependency to ease restoration

## PR Checklist
* [x] Closes #11978 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Test of restore and build on fresh repo copy passed.
2022-01-10 14:47:06 -08:00
Michael Niksa
3f385f11a1 Move to PGO Nuget (#11819)
To unify with WinUI, we're going to share an engineering component of this particular NuGet package full of scripts and utilities to make PGOing things easier.

This basically removes all of the scripts that I ~blatantly stole~ copied from https://github.com/microsoft/microsoft-ui-xaml and moves to the NuGet package that the team generates instead. A bunch of build things had to be massaged to make it work in our pipeline.
2022-01-10 14:46:51 -08:00
Michael Niksa
a3b9cd2369 Enable SBOM generation for Windows Terminal (#11908)
Microsoft will be providing a Software Bill of Materials for our products. This onboards the Windows Terminal product to the common engineering system task that can scavenge for this information within our build project (already recorded for internal compliance reasons) and present it in a machine-readable interchange format.

See also: https://devblogs.microsoft.com/engineering-at-microsoft/generating-software-bills-of-materials-sboms-with-spdx-at-microsoft/

This does not yet include packaging and distributing the SBOM with our final packages. We are waiting for that tooling to come online for MSIX. Guidance is "Coming Soon™️."

## References
- https://github.com/microsoft/dropvalidator/issues/216 - `cgmanifest.json` are not being pulled in yet, but I've been told internally this will fix it. I will double-check when I hear back on this issue.

## PR Checklist
* [x] Closes #11810 
* [x] I work here
* [x] I ran it and I see the manifest generated.
2022-01-10 14:45:25 -08:00
Dustin Howett
5f7c66bc0c [STABLE ONLY] Combined revert of Environment Block Changes
Revert "Fix environment block creation (#7401)"

This reverts commit 7886f16714.

(cherry picked from commit e46ba65665)

Revert "Always create a new environment block before we spawn a process (#7243)"

This reverts commit 849243af99.

References #7418

(cherry picked from commit 4204d2535c)
(cherry picked from commit f8e8572c23)
(cherry picked from commit cb4c4f7b73)
(cherry picked from commit afb0cac3e3)
(cherry picked from commit b25dc74a1d)
2022-01-10 14:20:59 -08:00
Mike Griese
757399650d Fix the cmdpal moving the infobar down (#11670)
Just read the code, it's immediately obvious what I messed up

Closes #11645

@DHowett turns out I was wrong, I could get this one done before 5 😜

(cherry picked from commit 3667678df1)
2021-12-13 20:50:46 -06:00
Comzyh
1ce8424ab7 Parse UTF-16 surrogates pairs for calculating pattern's position (#11915)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

Properly handle UTF-16 surrogates when calculating the position of matched pattern.

Fix #8709

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
b88ffb21b0/src/buffer/out/search.cpp (L335-L339)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #8709
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
use `Utf16Parser::Parse` to handle code points from U+010000 to U+10FFFF in UTF-16.

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

![image](https://user-images.githubusercontent.com/1068203/145421736-c842c7d4-0136-42d0-ad72-f004f58d9e3b.png)

also the case by @mas90  https://github.com/microsoft/terminal/issues/8709#issuecomment-884915485:

![image](https://user-images.githubusercontent.com/1068203/145420264-3fe220b4-42c5-44ac-aa94-4e604b164ed3.png)

(cherry picked from commit a2d96d6b1f)
2021-12-13 16:56:00 -06:00
Leonard Hecker
e0c4277777 Fix length calculation of GetConsoleCommandHistoryLengthA (#11897)
This is a primitive bug fix for GetConsoleCommandHistoryLengthA.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

(cherry picked from commit ca20bbde1e)
2021-12-13 16:56:00 -06:00
Schuyler Rosefield
3a51afc375 Make sure we dont access an invalid optional on close (#11857)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Clean up an invalid access that I introduced in #11440

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #11684
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

(cherry picked from commit 29e6235151)
2021-12-13 16:56:00 -06:00
Michael Niksa
a303c63b07 Tell PublishSymbols task about binaries as well as the PDB files (#11852)
We have been advised to give not only the PDB paths, but paths to the EXE and DLL files we produce, to the PublishSymbols build task. We are assured by our engineering systems teams that enlightening the task to all of this information helps it hook things up better somewhere between our build machine and the symbol server such that debugging is more robust, especially around thrown exception stacks.

## PR Checklist
* [x] Closes #11737 - main fix for feeding EXEs and DLLs into the symbol publisher
* [x] Closes #11860 - bonus fix because I noticed the PDB source linking wasn't working
* [x] I work here.
* [x] If it fits, it sits.

(cherry picked from commit 52235b0fb6)
2021-12-13 16:56:00 -06:00
Mike Griese
ccc74686a2 Add snap-layouts support to the Terminal (#11680)
Adds snap layout support to the Terminal's maximize button. This PR is
full of BODGY, so brace yourselves.

Big thanks to Chris Swan in #11134 for building the prototype.
I don't believe this solves #8795, because XAML islands can't get
nchittest messages

- The window procedure for the drag bar forwards clicks on its client
  area to its parent as non-client clicks.
- BODGY: It also _manually_ handles the caption buttons. They exist in
  the titlebar, and work reasonably well with just XAML, if the drag bar
  isn't covering them.
- However, to get snap layout support, we need to actually return
  `HTMAXBUTTON` where the maximize button is. If the drag bar doesn't
  cover the caption buttons, then the core input site (which takes up
  the entirety of the XAML island) will steal the `WM_NCHITTEST` before
  we get a chance to handle it.
- So, the drag bar covers the caption buttons, and manually handles
  hovering and pressing them when needed. This gives the impression that
  they're getting input as they normally would, even if they're not
  _really_ getting input via XAML.
- We also need to manually display the button tooltips now, because XAML
  doesn't know when they've been hovered for long enough. Hence, the
  `_displayToolTip` `ThrottledFuncTrailing`

## Validation
Minimized, maximized, restored down, hovered the buttons slowly, moved
the mouse over them quickly, they feel the same as before. But now with
snap layouts appearing.

## TODO!
* [x] I'm working on getting the ToolTips on the caption buttons back. Alas, I needed a demo of this _today_, so I'll fix that tomorrow morning.
* [x] mild concern: I should probably test Win 10 to make sure there wasn't weird changes to the message loop in win11 that means this is broken on win10.
* [x] I think I used the wrong issue number for tons of my comments throughout this PR. Double check that. Should be #9443, not #9447.

Closes #9443
I thought this took care of #8587 ~as a bonus, because I was here, and the fix is _now_ trivial~, but looking at the latest commit that regressed.

Co-authored-by: Chris Swan <chswan@microsoft.com>
(cherry picked from commit f2ebb21bd1)
2021-12-13 16:56:00 -06:00
Mike Griese
0c022811e6 Don't crash if we fail to BeginBufferedPaint (#11674)
Fixes MSFT:34673647, at least I'm pretty sure. That's only ever hit a few
times externally, and internally it's hitting a lot on 1.9.1942 builds, which
doesn't really make any sense.

(cherry picked from commit a74c37bbcd)
2021-12-13 16:56:00 -06:00
Sergey
83b482a05f Fix missing window border when use "win+arrow down" in fullscreen mode in Terminal (#11653)
Window sends an event that requests exit from fullscreen then SC_RESTORE messages is sent and it is in fullscreen mode.
Closes #10607

## Validation Steps Performed
Border and tabbar now appear after exiting fullscreen via "win+arrow down".

(cherry picked from commit 7aae2e9100)
2021-12-13 16:55:26 -06:00
Mike Griese
217196e592 Make sure to format the error message with an UNSIGNED int (#11667)
Closes #11556
![image](https://user-images.githubusercontent.com/18356694/139715591-b18ef7c1-2967-42a5-9528-2522220aa177.png)

(cherry picked from commit 8826cc028b)
2021-12-13 16:55:26 -06:00
James Holderness
ab683c00cc Default all G-sets to ASCII unless ISO-2022 is requested (#11658)
## Summary of the Pull Request

There is a non-zero subset of applications that randomly output _Locking Shift_ escape sequences which will invoke a character set from G2 or G3 into the left half of the code table. If those G-sets are mapped to Latin1, that can result in the terminal producing output that appears to be broken. This PR now defaults all G-sets to ASCII, to prevent an unintentional _Locking Shift_ from having any effect.

## PR Checklist
* [x] Closes #10408
* [x] CLA signed.
* [ ] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. Issue number where discussion took place: #10408

## Detailed Description of the Pull Request / Additional comments

Most other modern terminals also default to ASCII in all G-sets, so this shouldn't break any modern applications. Legacy 8-bit applications may still expect the G2 and G3 sets mapped to Latin1, but they would also need to have the ISO-2022 encoding enabled, so we can keep them happy by setting G2 and G3 correctly when the ISO-2022 encoding is requested.

## Validation Steps Performed

I've manually confirmed that `echo -e "\en"` and `echo -e "\eo"` no longer have any visible effect on the output (at least without first invoking another character set into G2 or G3). I've also confirmed that they do still work as expected (i.e. selecting Latin1) after enabling the ISO-2022 encoding.

(cherry picked from commit 27e042b784)
2021-12-13 16:55:26 -06:00
PankajBhojwani
4ad3156f42 Check that the control exists before we try to focus it (#11635)
## Summary of the Pull Request
When we are on a settings UI tab, `_GetActiveControl` returns a `nullptr`, make sure not to try and focus it in that case

## PR Checklist
* [x] Closes #11633
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
No longer crashes

(cherry picked from commit a7ce93a357)
2021-12-13 16:55:26 -06:00
Mike Griese
bf27a79ace Fix the wt action in defterm windows (#11646)
This is a pretty obvious typo in retrospect. Never hit it before, because in all non-defterm windows, the `_startupActions` always has one action.

* [x] Closes #11463

(cherry picked from commit b90f3605a2)
2021-12-13 16:55:26 -06:00
Ian O'Neill
3a615149da Ensure the background image path is displayed in the settings UI (#11580)
## Summary of the Pull Request
Ensures that the background image path is displayed in the settings UI.

## References
One of the items on #11353

## PR Checklist
* [x] Closes #11541
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA

## Validation Steps Performed
Set the background image path and saw that it was displayed in the settings UI.

(cherry picked from commit 9662bc6910)
2021-12-13 16:55:26 -06:00
Dustin L. Howett
dadee5bdaf Update Cascadia Code to 2111.01 (#11937)
This update fixes the bracket ligatures in italic.

See microsoft/cascadia-code#595 for more details.

(cherry picked from commit 246e57f1b2)
2021-12-13 16:41:24 -06:00
Leonard Hecker
4c364e9342 Use nearby fonts for font fallback (#11764)
This commit is a minimal fix in order to pass the
`IDWriteFontCollection` we create out of .ttf files residing next to our
binaries to the `IDWriteFontFallback::MapCharacters` call. The
`IDWriteTextFormat` is used in order to carry the font collection over
into `CustomTextLayout`.

## Validation
* Put `JetBrainsMono-Regular.ttf` into the binary output directory
* Modify `HKCU:\Console\*\FaceName`  to `JetBrains Mono`
* Launch OpenConsole.exe
* OpenConsole uses JetBrains Mono ✔️

Closes #11032
Closes #11648

(cherry picked from commit 131f5d2b32)
2021-12-13 14:19:52 -06:00
Mike Griese
aaabce77c7 Fix the opacity slider (#11643)
I can't even write a description for this. Just read the code change, you'll see what I goofed.

Regressed in #11372

Closes #11555

(cherry picked from commit 1cedac6a33)
2021-12-13 14:19:52 -06:00
Leonard Hecker
c9cde49716 Fix loading of fragments that update multiple profiles (#11598)
The "updates" key is an alternative "guid" key for fragment profiles.
But SettingsLoader::_appendProfile stores and deduplicates profiles according
to their "guid" only. We need to modify the function to optionally store
profiles by their "updates" key as well, otherwise multiple fragment
profiles without "guid" might collide as they produce the same default GUID.

## PR Checklist
* [x] Closes #11597
* [x] I work here
* [ ] Tests added/passed
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
* Unit tests pass ✔️
* Issue #11597 doesn't reproduce anymore ✔️

(cherry picked from commit fe26a6efc0)
2021-12-13 14:19:52 -06:00
Mike Griese
5198c8e2e4 Make sure the infobar is inserted before the tab content, not on top of (#11609)
Fixes #11606

This is weird, but the infobars would appear totally on top of the
TerminalPage when `showTabsInTitlebar:false`. This would result in the infobar
obscuring the tabs.

Now, the infobars are strictly inserted after the tabs, before the content. So
when they appear, they will reduce the amount of space usable for the control.
That is a little annoying, but preferable to the tabs totally not existing.

Relevant conversation notes from #10798:

> > If the info bar is not local to the tab, then its location between the tab
> > bar (when the title bar is hidden) and the terminal panes feels
> > misleading. Should it instead be above the tab bar or below the terminal
> > panes?
>
> You're... not wrong here. It's maybe not the best place for it, but _on top_
> of the tabs would look insane, and probably wouldn't even work easily, given
> the way we reparent the tab row into the titlebar.
>
> In the pane itself would make more sense, but that runs abreast of all sorts
> of things like #9024, #4998, which might make more sense.

I'm just gonna go with this now, because it's _better_ than before, while we
work out what's _best_.

![gh-11606-fix](https://user-images.githubusercontent.com/18356694/138729178-b96b7003-0dd2-4521-8fff-0fd2a5989f22.gif)

(cherry picked from commit a916a5d9de)
2021-12-13 14:19:52 -06:00
Leonard Hecker
2aa2458b22 Compile OpenConsoleProxy without CRT (#11610)
After this commit OpenConsoleProxy will be built without a CRT.
This cuts down its binary size and DLL dependency bloat.
We hope that this fixes a COM server activation bug if the
user doesn't have a CRT installed globally on their system.

Fixes #11529

(cherry picked from commit def1bdd693)
2021-12-13 14:19:52 -06:00
Leonard Hecker
aacfc2a424 Fix AltGr not working in the settings UI (#11808) (#11814)
Since the settings UI's input fields behave similarly to the terminal's input,
`TerminalPage::_KeyDownHandler` also needs to behave similarly to
`TermControl::_KeyHandler`. This commit copies all relevant code
over from the latter into the former, including the suppression
of AltGr keys for keychord/action handling.

## PR Checklist
* [x] Closes #11788
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* Use a German keyboard layout
* Open 2 regular tabs and 1 settings tab and focus an input field
* AltGr+2 produces the character ² ✔️
* Ctrl+Alt+2 opens the second tab ✔️

(cherry picked from commit 80f8383860)
2021-12-01 05:38:26 -06:00
Leonard Hecker
39b72f78c3 Fixed VsDevCmd command line quoting (#11554)
(cherry picked from commit 5cd9663269)
2021-10-20 21:59:10 +02:00
PankajBhojwani
89674ac4fb Updating PGO branch 2021-10-19 17:29:16 -07:00
Schuyler Rosefield
6bf1507a6c Try to fix crash on close with saving enabled (#11440)
Don't crash if we try to save the window layout while we are closing, and try to avoid saving at all.

Might impact #11354 

## Detailed Description of the Pull Request / Additional comments
- Revoke the event handler/save throttler so we don't even try to get the window layout when we are closing
- Try to check for nullptrs, but then apply `try {} CATCH_LOG()` liberally

## Validation Steps Performed
The happy path of saving normally is still fine, but I haven't been unlucky enough to trigger the crash myself.
2021-10-19 17:12:18 -07:00
Leonard Hecker
5a23029dac Further reduce number of generated VS profiles (#11489)
This commit reduces the number of generated VS profiles from 6 down to just 2
per VS instance. The reason we did this is out of concern of overwhelming or
annoying new users with too many profiles. Especially since it's far easier
at the moment to add new generators compared to removing them.

As before only the latest instance is not hidden by default.

## PR Checklist
* [x] I work here
* [x] Tests added/passed
* [x] As discussed in a Team Sync meeting

## Validation Steps Performed
* Installed Visual Studio 2019 and 2022 Preview
* A profile for both is generated, while the 2019 one is hidden by default ✔️
* $env:VSCMD_ARG_TGT_ARCH is x64 on my AMD64 machine ✔️
2021-10-19 23:52:00 +00:00
Mike Griese
284257a383 Add even MORE logging for defterm (#11537)
Considering the number of reports of "defterm isn't working (mysteriously)", I figured more logging current hurt. I also added a wprp profile for the defterm logging as well, which should capture conhost side things as well. 

From an elevated conhost:
```
wpr -start path\to\Terminal.wprp!Defterm.Verbose
wpr -stop %USERPROFILE%\defterm-trace.etl
```

* [x] I work here
* [x] relevant to: #10594, #11529, #11524.
2021-10-19 13:29:18 -07:00
NotWearingPants
0d5af3fedc Remove double-space in defaults.json (#11518)
There was a double-space after a colon in `defaults.json` and `defaults-universal.json`.
2021-10-18 16:25:13 -05:00
NotWearingPants
fd93c54ae3 Change action names in schema to match without regex (#11520)
## Summary of the Pull Request
Currently when configuring the action
```json
{ "command": { "action": "closeTabsAfter" } }
```
we get a schema error in VSCode: `Matches multiple schemas when only one must validate.`.

The problem is that it matches both `closeTabsAfter` and `closeTab`, since the schema uses regex patterns to match instead of plain strings. I swapped the usage of `"pattern"` with `"const"` for all actions.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan

## Detailed Description of the Pull Request / Additional comments

## Validation Steps Performed
I checked and this action configuration no longer errors.
2021-10-18 16:24:35 -05:00
Leonard Hecker
c1d326693c Remove debug logging for PSReadline on newlines (#11486)
Up until this commit PSReadline caused OutputDebugString to be called
with a complex log message to on every newline. At the time of writing,
Visual Studio's Output window is fairly slow and after this change newlines
feel a fair bit snappier when running under Visual Studio's debugger.

## Validation Steps Performed
* pwsh.exe continues to work correctly ✔️
2021-10-18 10:20:34 -07:00
Leonard Hecker
2cf31ac72d Remove last remaining winrt::hstring allocation during text output (#11487)
ControlCore::FontFaceName() is called 10/s by TSFInputControl.
The getter was modified to cache the STL string in a hstring allowing
us to return a value without temporary allocations during runtime.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* Font face and size changes properly update TSFInputControl ✔️
2021-10-18 09:55:38 -07:00
NotWearingPants
02dd463b35 Linked missing action command objects in schema (#11519)
## Summary of the Pull Request
Currently when configuring the action
```json
{ "command": { "action": "commandPalette", "launchMode": "commandLine" }, "key": "ctrl+shift+p" }
```
or
```json
{ "command": { "action": "multipleActions", "actions": [{ "action": "paste" }] }, "key": "ctrl+shift+v" }
```
we get a schema error in VSCode. These object variants of the actions were not configured properly in the schema, so I fixed it.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan

## Detailed Description of the Pull Request / Additional comments
In the schema there is a big `oneOf` for the `command` of an action under `actions`.
Commands that also accept extra arguments have an object type defined for it.
The `commandPalette` and `multipleActions` commands accept extra arguments, and also have matching `CommandPaletteAction` and `MultipleActionsAction` object types defined, but they are unused.
So I added them to the `oneOf` array in the correct placement.

## Validation Steps Performed
2021-10-18 11:42:31 -05:00
NotWearingPants
51c3011950 Fix quoted boolean defaults in schema (#11517)
## Summary of the Pull Request

The `settings.json` schema had `"default"`s for some boolean settings set as quoted strings (`"true"` / `"false"`), so I removed the quotes.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan

## Detailed Description of the Pull Request / Additional comments

VSCode autocompletes the default value when you select the setting in intellisense, so it autocompleted a string which caused a schema error. Booleans should be JSON booleans, not quoted.

## Validation Steps Performed
2021-10-18 11:42:08 -05:00
Dmitriy Fishman
1c8b71b6e7 Fix a typo in Niksa.md (#11506) 2021-10-15 17:46:49 -05:00
Dmitriy Fishman
b3cc618af8 doc: Fix a UKism in CONTRIBUTING.md (#11505) 2021-10-15 17:46:26 -05:00
Carlos Zamora
02ac246807 Properly initialize XamlUiaTextRange with ProviderFromPeer (#11501)
## Summary of the Pull Request
As a part of the Interactivity split, `TermControlAutomationPeer` had to be split into `TermControlAutomationPeer` (TCAP) and `InteractivityAutomationPeer` (IAP). Just about all of the functions in `InterativityAutomationPeer` operate by calling the non-XAML UIA Provider then wrapping the resulting `UIATextRange` into a XAML format (a `XamlUiaTextRange` [XUTR]). As a part of that XUTR constructor, we need a reference to the parent provider.

We generally get that via `ProviderFromPeer()`, but IAP's `ProviderFromPeer()` returned null (presumably because IAP isn't in the UI tree, whereas TCAP is directly registered as the automation peer for the `TermControl`).

It looks like some screen readers didn't care (like NVDA, though there may be a chance we just didn't encounter an issue just yet), but Narrator definitely did.

The fix was to provide XUTR constructors the `ProviderFromPeer` from TCAP, _not_ IAP. To accomplish this, IAP now holds a weak reference to TCAP, and provides the `ProviderFromPeer` when needed. We can't cache this result because there is no guarantee that it won't change.

Some miscellaneous changes include:
- `TermControl::OnCreateAutomationPeer` now returns the existing auto peer instead of always creating a new one
- `TCAP::WrapArrayOfTextRangeProviders` was removed as it was unused (normally, this would be directly affected by the main `ProviderFromPeer` change here)
- `XUTR::GetEnclosingElement` is now hooked up to trace logging for debugging purposes

## References
Introduced in #10051
Closes #11488 

## Validation Steps Performed
 Narrator scan mode now works (verified with character, word, and line navigation)
 NVDA movement still works (verified with word and line navigation)
2021-10-13 23:01:43 +00:00
Dustin L. Howett
a89c3e2f85 Add an Open Settings link to the "Default Terminal" tip (#11491)
This commit switches the [X] button in the info bar to permanently
dismiss the tip and fixes a focus transition issue.

Closes #11483
2021-10-12 22:12:21 +00:00
MPela
462d8003a7 Dismiss any open content dialog when window is moved (#11485)
## Summary of the Pull Request
When the window moves, hide any visible content dialog (only one can be shown at a time) and ensure its associated async operation is terminated.

#10922 dismisses any open popups when the window is moved or any scroll viewer scrolls. However, if you just close a Popup from the UI tree, the async operation associated to a ContentDialog (started with `dialog.ShowAsync`) does not terminate. The dialog lock that prevents opening multiple dialogs at the same time is not released, and no further dialog can be shown. 
Explicitly dismissing the only visible ContentDialog using its `Hide` method terminates the operation.

## Validation Steps Performed
Manual tests, open up dialogs and move the window (like in #11425)

References #10922 
Closes #11425
2021-10-12 18:00:06 +00:00
PankajBhojwani
275cdcf63f Enable the editable actions page in the SUI (#11481) 2021-10-12 15:56:48 +00:00
Leon Liang
08e36123b3 Add logging for default terminal (#11458)
This PR adds some `TraceLogging` for default terminal, namely:
- [x] successfully receiving terminal handoffs
- [x] failing to receive terminal handoffs
- [x] default terminal selection changes

Closes #11452
2021-10-12 15:56:17 +00:00
Leonard Hecker
b036cab850 Enable fast floating point model and fast debug linking (#11466)
This commit enables /fp:fast. This doubles the performance of the Delta E
computation in #11095 for instance. Additionally it re-enables two options for
debug builds which are normally enabled by default by Visual Studio.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* No change in binary size
* No obvious change in behavior
2021-10-11 21:02:15 +00:00
Dustin L. Howett
4a3e50cb16 Enable the "Defaults" settings page in Stable (#11453)
This change enables access to the Defaults page in stable builds of
terminal. It is intended that we backport this feature flag edit to
1.11, so that Defaults can roll out with 1.11 when it becomes stable.
2021-10-11 16:21:32 +00:00
Leonard Hecker
0ab1529487 Improve til::gen_random documentation (#11465) 2021-10-11 17:59:40 +02:00
Mike Griese
8dd317313b Clear out state.json when we find and empty settings.json (#11448)
If we find that the settings file doesn't exist, or is empty, then let's quick
delete the state file as well. If the user does have a state file, and not a
settings, then they probably tried to reset their settings. It might have data
in it that was only relevant for a previous iteration of the settings file. If
we don't, we'll load the old state and ignore all dynamic profiles (for
example)!

We'll remove all of the data in the `ApplicationState` object and reset it to
the defaults.

This will delete the state file!

That's the sure-fire way to make sure the data doesn't come back. If we leave
it untouched, then when we go to write the file back out, we'll first re-read
it's contents and try to overlay our new state. However, nullopts won't remove
keys from the JSON, so we'll end up with the original state in the file.

* [x] Closes #11119
* [x] Tested on a cold launch of the Terminal with an existing `state.json`
and an empty `settings.json`
* [x] Tested a hot-reload of deleting the `settings.json`
2021-10-11 15:51:47 +00:00
Leonard Hecker
479ef264b2 Implement basic profile matching (#11390)
This implements command line matching for `CascadiaSettings::GetProfileForArgs`.
The command lines for all user profiles are resolved to absolute file paths,
argument quotes are standardized ("canonicalized") and the results are cached.

When `GetProfileForArgs` is called with a Commandline() value, we "canonicalize"
the argument as well and find the profile that is the longest prefix.
If none could be found the default profile is returned.

## PR Checklist
* [x] Closes #9458
* [x] Closes #10952
* [x] I work here
* [ ] Tests added/passed

## Validation Steps Performed

* Open a `cmd.exe` tab in the store-version of WT
* Run `start cmd`
  --> A tab with the `cmd.exe` profile opens
* Run `start pwsh.exe`
  --> A tab with the PowerShell 7 profile opens
* Run PowerShell 7 from the start menu
  --> A tab with the PowerShell 7 profile opens
* Create a symlink for PowerShell 7 and launch `pwsh.exe` from there
  --> A tab with the PowerShell 7 profile opens
2021-10-08 00:40:10 +00:00
PankajBhojwani
dd5dbb2a40 Implement the Delta E algorithm to improve color perception (#11095)
- Implements the Delta E algorithm
- Uses the Delta E algorithm to precalculate adjusted foreground values based on possible foreground/background color pairs in the color table
- Adds a setting to use the adjusted foreground values when applicable

## PR Checklist
* [x] Closes #2638
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
Before:
<img width="759" alt="color before" src="https://user-images.githubusercontent.com/26824113/131576768-b3b9eebd-5933-45de-8da8-88a985070312.png">

After (note dark blue):
<img width="760" alt="color after" src="https://user-images.githubusercontent.com/26824113/133158807-4e63198f-8a49-4d03-914e-55a5ad57d725.png">
2021-10-07 22:43:17 +00:00
Mike Griese
bc4f410788 Wire up RadioButtons as groups in UIA (#11442)
I thought that microsoft/microsoft-ui-xaml#3183 might just fix this for us, but it didn't. We've got our RadioButton's all up in SettingsContainers, so they all think they're `AutomationProperties.AccessibilityView="Raw"` for some reason. If you simply add the `Content` to these, then they all end up correct in Accessibility Insights

## PR Checklist
* [x] Will take care of #11248 but I can't be the one to close it.
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
2021-10-07 17:46:04 +00:00
Leonard Hecker
2b1468eaa2 Add a information popup about default terminals (#11397)
This commit adds a simple information popup about default terminals,
guiding first-time Windows 11 users into changing the default terminal.

## Validation Steps Performed
* Info bar pops up on Windows 11 ✔️
* Info bar can be dismissed persistently ✔️
2021-10-07 17:44:03 +00:00
Mike Griese
e1c830dde0 Make sure all the commandlines are fully qualified (#11437)
This was originally in #11308. Thought we should check it in for 1.12 even
though that won't merge this release. Should slightly mitigate the number of
users that see this warning.
2021-10-07 12:18:11 -05:00
Leonard Hecker
84e7ec4f96 Fix layering issues with CascadiaSettings::_createNewProfile (#11447)
`CascadiaSettings::_createNewProfile` failed to call `_FinalizeInheritance`.
This commits fixes the issue and adds a stern warning for future me.

## PR Checklist
* [x] Closes #11392
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Open settings UI
* Modify font size in base layer
* _Don't_ save
* Duplicate any profile with default font size
* Ensure the duplicated profile shows the modified base layer font size ✔️
2021-10-07 16:30:34 +00:00
Mike Griese
694c6b263f When enabling opacity on win10, automatically enable acrylic (#11372)
In #11180 we made `opacity` independent from `useAcrylic`. We also changed the mouse wheel behavior to only change opacity, and not mess with acrylic.

However, on Windows 10, vintage opacity doesn't work at all. So there, we still need to manually enable acrylic when the user requests opacity.

* [x] Closes #11285

SUI changes in action:

![auto-acrylic-win10](https://user-images.githubusercontent.com/18356694/136281935-db9a10f4-e0ad-4422-950b-0a01dc3e12c0.gif)
2021-10-07 11:39:20 +00:00
Mike Griese
bd8bfa13bb Fix opening the debug tap (#11445)
It's possible that we're about to be started, _before_
our paired connection is started. Both will get Start()'ed when
their owning TermControl is finally laid out. However, if we're
started first, then we'll immediately start printing to the other
control as well, which might not have initialized yet. If we do
that, we'll explode.

Instead, wait here until the other connection is started too,
before actually starting the connection to the client app. This
will ensure both controls are initialized before the client app
is.

Fixes #11282

Tested: Opened about 100 debug taps. They all worked. :shipit:
2021-10-06 16:11:09 -05:00
Leonard Hecker
c727762602 Fix null pointer exceptions for default constructed CascadiaSettings instances (#11428)
`CascadiaSettings` is default constructed when human readable error messages are
returned. Even in such cases we need to ensure that all fields are properly
initialized, as a caller might decide to call a `GlobalSettings` getter.
Thus a crash occurred whenever a user was hot-reloading their settings file with
invalid JSON as other code then tried to compare the `GlobalSettings()`.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Start Windows Terminal and ensure the settings load fine
* Add `"commandline": 123` to any of the generated profiles in settings.json
* The application doesn't crash and shows a warning message
2021-10-06 17:02:53 +00:00
Leonard Hecker
35ce8cc858 Fix default terminal setting dropdown (#11430)
WinUI/XAML requires the `SelectedItem` to be member of the list of
`ItemsSource`. `CascadiaSettings::DefaultTerminals()` is such an `ItemsSource`
and is called every time the launch settings page is visited.
It calls `DefaultTerminal::Available()` which in turn calls `Refresh()`.
While the `SelectedItem` was cached in `CascadiaSettings`, the value of
`DefaultTerminals()` wasn't. Thus every time the page was visited, it refreshed
the `ItemsSource` list without invalidating the current `SelectedItem`.

This commit prevents such accidental mishaps from occurring in the future,
by moving the responsibility of caching solely to the `CascadiaSettings` class.

## PR Checklist
* [x] Closes #11424
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* Navigating between SUI pages maintains the current dropdown selection ✔️
* Saving the settings saves the correct terminal at `HKCU:\Console\%%Startup` ✔️
2021-10-06 16:58:09 +00:00
Mike Griese
925b05a3b7 Center-align the shield with the other tab row icons (#11441)
I started from here:
9052972906/dev/CommonStyles/Button_themeresources_v1.xaml (L121)

but adding a padding of 3 was still off by one pixel, so it's 4 now.

_enhance.png_
![image](https://user-images.githubusercontent.com/18356694/136219225-3fcffd48-79b4-4efc-a4c3-4b59f9878962.png)

* [x] closes #11421
2021-10-06 16:55:55 +00:00
Carlos Zamora
43ce9fda09 Refresh frame margins when moving between monitors (#11412)
## Summary of the Pull Request

Refresh the DPI and frame margins when we move the window between different DPI monitors.

## PR Checklist
Closes #11367
2021-10-06 11:34:53 +00:00
Carlos Zamora
14d068f73b Fix crash and empty action in SUI Actions Page (#11427)
## Summary of the Pull Request
Fixes two issues related to SUI's Actions page:
1. Crash when adding an action and setting key chord to one that is already taken
   - **Cause**: the new key binding that was introduced with the "Add new" button appears in `_KeyBindingList` that we're iterating over. This has no `CurrentKeys()`, resulting in a null pointer exception.
   - **Fix**: null-check it
2. There's an action that appears as being nameless in the dropdown
   - **Cause**: The culprit seems to be `MultipleActions`. We would register it, but it wouldn't have a name, so it would appear as a nameless option.
   - **Fix**: if it has no name, don't register it. This is also future-proof in that any new nameless actions won't be automatically added.

Closes #10981
Part of #11353
2021-10-06 11:33:05 +00:00
Leon Liang
f7b5b5caf8 Enable DefApp hooks for stable (#11423)
Uncommenting parts of stable's AppXManifest to allow defapp to work with it.
2021-10-06 11:32:14 +00:00
Leonard Hecker
0b552e1ae8 Fix failing TestHostApp unit tests (#11394)
This commit fixes various failing TestHostApp unit tests.
Most of these broke as part of 168d28b (#11184).

## PR Checklist
* [x] Closes #11339
* [x] I work here
* [x] Tests added/passed
2021-10-05 18:21:03 +00:00
Mike Griese
6295c8cc45 Fix the tab color, part III (#11413)
I've had a hard time with the tab colors this week.

Turns out that setting the background to nullptr will make the tabviewitem invisible to hit tests. `Transparent`, on the other hand, is totally valid, and the expected default. 

Tabs as of this commit:

![tab-color-fix-3](https://user-images.githubusercontent.com/18356694/135915272-ff90b28b-f260-493e-bf0b-3450b4702dce.gif)

## PR Checklist
* [x] Closes #11382
* [x] I work here

This low-key reverts a bit of #11369, which fixed #11294, which regressed in #11240
2021-10-05 15:28:24 +00:00
Yoshiko
3f1befb06e Fix Touch Keyboard invocation issue (#11389)
This fixes an issue that Touch Keyboard is not invoked when user taps on the PowerShell. 

Before this change, it was returning small rectangle on the right of the cursor. Touch Keyboard should be invoked by tapping anywhere inside the console.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments
ITfContextOwner::GetScreenExt is used to define rectangle that can invoke Touch Keyboard. 
https://docs.microsoft.com/en-us/windows/win32/api/msctf/nf-msctf-itfcontextowner-getscreenext

## Validation Steps Performed
* [x] Touch keyboard was invoked by tapping inside the Console while Hardware Keyboard was not attached.
* [x] Selecting text worked as expected without invoking touch keyboard.
* [x] Long tapping the console invoked Touch Keyboard. I would like to confirm if this is the expected behavior.
2021-10-04 14:29:56 +00:00
NotWearingPants
e5180fe880 Fix globalSummon.dropdownDuration not saving correctly (#11401)
## Summary of the Pull Request

In `settings.json` there's an `actions` array to configure keybindings.
The action `globalSummon` has an argument called `dropdownDuration`.
The settings editor deleted this argument from the settings because of a typo in `ActionArgs.h`.

## PR Checklist
* [x] Closes #11400
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [ ] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan.

## Detailed Description of the Pull Request / Additional comments

There was a `JsonUtils::GetValueForKey` instead of a `JsonUtils::SetValueForKey`.
This is what happens when such code is not autogenerated.

## Validation Steps Performed

None
2021-10-04 13:15:50 +00:00
Ian O'Neill
703e349fd3 Ensure "Reset to inherited value" button works for opacity (#11391)
## Summary of the Pull Request
Fixes the "Reset to inherited value" button for the opacity slider and removes the unwanted padding between the header and the control.

## PR Checklist
* [x] Closes #11352
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
Manually tested
2021-10-04 12:42:46 +00:00
NotWearingPants
856081229f [IslandWindow.cpp] Avoid double-fetching dropdownDuration (#11383)
## Summary of the Pull Request
The code saved `args.DropdownDuration()` to a local and then called the function again, instead of using the local.
Changed to use the local.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan.

## Detailed Description of the Pull Request / Additional comments

I think this getter simply accesses a member on `args`, it doesn't parse the settings or anything, so compiler optimizes it, but seemed to make more sense to use the local.
2021-10-04 12:40:15 +00:00
Schuyler Rosefield
b2fd65c601 Try to persist the Pane's working directory if we know what it is. (#11374)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Try to save the working directory if we know what it is (just copied what was done in duplicating a pane). I overlooked this in my original implementation that always used the settings StartingDirectory.

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References
#9800 

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Tried setting the working directory using the OSC 9;9 escape and confirmed that the directory saves correctly.
2021-10-04 12:39:29 +00:00
NotWearingPants
99b1190734 Fix type of id in focusPane action in setttings schema (#11395)
## Summary of the Pull Request

The type of the `"id"` argument of the `focusPane` action under `"actions"` in the `settings.json` schema was incorrectly set to a string.
It's actually expecting a non-negative number, and defaults to 0.
So I fixed the schema.

## PR Checklist
* [x] Closes #11393
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan.

## Detailed Description of the Pull Request / Additional comments



## Validation Steps Performed

I've validated that a string makes Windows Terminal complain it's a string and not a number, and that a number works as expected, and that the default is indeed zero.
2021-10-04 07:38:33 -05:00
Leonard Hecker
e5293b7814 Fix all fragments not loading when one is badly formed (#11346)
This commit introduces a number of poor abstractions to split
`SettingsLoader::_parse` into `_parse` for content in the format of the user's
settings.json and `_parseFragment` which is specialized for fragment files.
The latter suppresses exceptions and supports the "updates" key for profiles.

## PR Checklist
* [x] Closes #11330
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Wrote the following to
  `%LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\test\test.json`:
  ```json
  {
    "profiles": [
      {
        "name": "bad",
        "unfocusedAppearance": ""
      },
      {
        "name": "good"
      },
      {
        "updates": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
        "background": "#333"
      }
    ]
  }
  ```
* Ensured that "bad" is ignored ✔️
* Ensured that "good" shows up and works ✔️
* Ensured that the pwsh profile has a gray background ✔️
2021-10-01 22:54:23 +00:00
Mike Griese
85f067403d Replace the UWP file export with the shell32 one (#11365)
Just like in #9760, we can't actually use the UWP file picker API, because it will absolutely not work at all when the Terminal is running elevated. That would prevent the picker from appearing at all. So instead, we'll just use the shell32 one manually. 

This also gets rid of the confirmation dialog, since the team felt we didn't really need that. We could maybe replace it with a Toast (#8592), but _meh_

* [x] closes #11356
* [x] closes #11358
* This is a lot like #9760
* introduced in #11062
* megathread: #9700
2021-10-01 18:33:22 +00:00
Carlos Zamora
6657d2c3e5 [deadlock fix] Remove lock for SIUP::GetSelectionRange() (#11386)
## Summary of the Pull Request
The deadlock was caused by `ScreenInfoUiaProviderBase::GetSelection()` calling `TermControlUiaProvider::GetSelectionRange` (both of which attempted to lock the console). This PR removes the lock and initialization check from `TermControlUiaProvider`. It is no longer necessary because the only one that calls it is `SIUPB::GetSelection()`.

Additionally, this adds some code that was useful in debugging this race condition. That should help us figure out any locking issues that may come up in the future.

## References
#11312
Closes #11385 

## Validation Steps Performed
 Repro steps don't cause hang
2021-09-30 22:15:20 +00:00
Heath Stewart
37e8769b37 Show only latest VS, VC prompts by default (#11326)
## Summary of the Pull Request

Similar to `vswhere -latest`, show only the latest Visual Studio command prompts / developer PowerShell. This was tested by deleting the local package state and testing against fresh state with both VS2019 and VS2022 Preview installed, and indeed VS2022 Preview (both cmd and powershell) show. The other profiles were generated but hidden by default.

## References

Modification of PR #7774

## PR Checklist
* [x] Closes #11307
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments

The sort algorithm is the same basic algorithm I used in https://github.com/microsoft/vswhere. It sorts first by installation version with a secondary sort based on the install date in case the installation versions are the same.

## Validation Steps Performed

With both VS2019 and VS2022 Preview installed, I made sure the initial state was expected, and tried different combinations of hiding and unhiding generated entries, and restarted Terminal to make sure my settings "stuck".
2021-09-29 22:03:05 +00:00
Michael Niksa
d869913cfd Set min version for Release Engineering script to prevent weird errors on inbox Powershell (#11351)
Set min version for Release Engineering script to prevent weird errors on inbox Powershell
2021-09-29 14:59:56 -07:00
Mike Griese
cf00ad7ad4 Add automation names to some controls that were missing them (#11364)
All these controls didn't have `Name`s assigned, and Accessibility Insights doesn't like that. Their parents did, but the actual focusable elements themselves didn't. So I've just taken the nearby headers for these things and slapped them in as the Automation names for these controls.

I verified that each of these automated tests in Accessibility Insights pass again. 

* Will do the thing to #11155 but we need confirmation before that can be closed.
2021-09-29 21:58:26 +00:00
Mike Griese
ba239026f3 Allow the entire Tab to be hit testable again (#11369)
DESPITE the fact that there's a `Background()` API that we
could just call like:

```c++
  TabViewItem().Background(deselectedTabBrush);
```

We actually can't, because it will make the part of the tab that
doesn't contain the text totally transparent to hit tests. So we
actually _do_ still need to set `TabViewItemHeaderBackground` manually.

* Regressed in #11240
* Root cause up in https://github.com/microsoft/microsoft-ui-xaml/pull/3769
* [x] closes #11294
2021-09-29 21:57:58 +00:00
Mike Griese
d25ca26142 Always init the BG opacity with the renderer (#11368)
Missed this in #11180. I forgot to init the BG opacity with the renderer on startup, because that matters when you have `"antialiasingMode": "cleartype",`.

Repro json
```json
{
    "commandline": "cmd.exe",
    "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
    "hidden": false,
    "opacity": 35,
    "antialiasingMode": "cleartype",
    "padding": "0",
    "name": "Command Prompt"
},
```

* [x] Fixes #11315
2021-09-29 21:55:44 +00:00
James Holderness
dacff61f88 Use the til::enumset type for the GridLines enum in the renderers (#11345)
## Summary of the Pull Request

This replaces the `GridLines` enum in the renderers with a `til::enumset` type, avoiding the need for the various `WI_IsFlagSet` macros and flag operators.

## References

This is followup to PR #10492 which introduced the `enumset` class.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed.
* [ ] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan.

## Validation Steps Performed

I've manually confirmed that all the different gridlines are still rendering correctly in both the GDI and DX renderers.
2021-09-29 10:48:32 +00:00
Mike Griese
c0574f5ece Remove the fallback to 50% opacity when only useAcrylic is set (#11363)
This logic was seemingly redundant. There's two cases I'm looking at here:

#### Case 1
```jsonc
    "defaults":
    {
        "opacity": 35
    },
    "list":
    [
        {
            "commandline": "cmd.exe",
            "name": "Command Prompt"
        },
```

In this case, we wouldn't set the `TerminalSettings` Opacity to .35, we'd set it to 1.0, because the profile didn't have an `opactity`.

#### Case 2
```jsonc
    "defaults":
    {
        "useAcrylic": true
    },
    "list":
    [
        {
            "commandline": "cmd.exe",
            "name": "Command Prompt"
        },
```

In this case we still want to have an acrylic effect. Previously, we'd default this effect to 50% opaque. I'm not sure that we can actually get that anymore. BUT it turns out, we _can_ have 100% opacity and HostBackdropAcrylic. It is very subtle, but is maybe something we should be allowing anyways. It kinda looks like:
![image](https://user-images.githubusercontent.com/18356694/135168469-35d1f55b-58d1-4ee3-a717-76000c2574b9.png)



* [x] Fixes #11355
* [x] Regressed in #11180 
* [x] I work here
2021-09-29 10:26:20 +00:00
Mike Griese
6939112820 Minor typos in 1.12 features in SUI (#11362)
* [x] Fixes a bunch of the checkboxes in #11352
* [x] Fixes one of the boxes in #11353
* [x] The opacity warning -> error gibberish was fixed with the change to `DeserializationError` - `asCString` only works if the `JsonValue` is a string already.
2021-09-29 10:24:46 +00:00
Leonard Hecker
856f8764ce Fix compatibility issues with profiles.schema.json (#11360)
This fixes two issues with profiles.schema.json:
* The `$schema` should not end in a `#`
* `$defs` is the official reserved keyword for schema re-use

See: http://json-schema.org/draft/2020-12/json-schema-core.html

## PR Checklist
* [x] I work here
* [x] Tests added/passed
* [x] Schema updated

## Validation Steps Performed

The previous schema didn't pass https://jschon.dev/, the new schema does.
2021-09-29 05:23:38 -05:00
Mike Griese
3b3b72e9cf Replace null with "null" for types in the schema (#11350) 2021-09-28 14:43:51 -05:00
Schuyler Rosefield
43297315ba Add the ability to interact with subtrees of panes (#11153)
This commit adds the ability to interact with subtrees of panes. 

Have you ever thought that you don't have enough regression testing to
do? Boy do I have the PR for you! This breaks all kinds of assumptions
about what is or is not focused, largely complicated by the fact that a
pane is not a proper control. I did my best to cover as many cases as I
could, but I wouldn't be surprised if there are some things broken that
I am unaware of.

Done:
- Add `parent` and `child` movement directions to move up and down the
  tree respectively
- When a parent pane is selected it will have borders all around it in
  addition to any borders the children have.
- Fix focus, swap, split, zoom, toggle orientation, resize, and move to
  all handle interacting with more than one pane.
- Similarly the actions for font size changing, closing, read-only, clearing
   buffer, and changing color scheme will distribute to all children.
- This technically leaves control focus on the original control in the
  focused subtree because panes aren't proper controls themselves. This
  is also used to make sure we go back down the same path with the
  `child` movement.
- You can zoom a parent pane, and click between different zoomed
  sub-panes and it won't unzoom you until you use moveFocus or another
  action. This wasn't explicitly programmed behavior so it is probably
  buggy (I've quashed a couple at least). It is a natural consequence of
  showing multiple terminals and allowing you to focus a terminal and a
  parent separately, since changing the active pane directly does not
  unzoom. This also means there can be a disconnect between what pane is
  zoomed and what pane is active.

## Validation Steps Performed
Tested focus movement, swapping, moving panes, and zooming.

Closes #10733
2021-09-28 19:16:05 +00:00
Schuyler Rosefield
75e2b5fae7 Persist window layout cont. save multiple windows (#11083)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. 

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Also closes #766
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Rough changelog:
Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action.

For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions.

- create a new window for each saved layout, or
- take the first layout for our self and then a new window for each other layout.

This also saves the layout when the quit action is taken.

Misc changes
- A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now.
- All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect.
- Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below)
- Now save runtime tab color and window names
- Only enabled for non-elevated windows
- Add some change tracking to ApplicationState

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 21:18:39 +00:00
Leonard Hecker
2d583fc860 Fix fragments that update other profiles (#11343)
`SettingsLoader::_parse` used to skip profiles which didn't have either a "guid"
or "name" field, due to #9962. This is however wrong for fragment loading, as
fragments can alternatively use an "updates" field instead of guid/name.

`SettingsLoader::_parse` was updated to allow profiles with this alternative
field during fragment loading.

## PR Checklist
* [x] Closes #11331
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Wrote the following to
  `%LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\test\test.json`:
  ```json
  {
    "profiles": [
      {
        "updates": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
        "background": "#FFD700"
      }
    ]
  }
  ```
2021-09-27 17:09:53 +00:00
Sujal Gupta
5542e727d0 fix typo (#11338) 2021-09-27 10:23:28 -05:00
snxx
5fa379e707 .gitattributes: removed php display in the project (#11329)
Since `*.inc` uses `cpp`, I changed the display via `.gitattributes`.
2021-09-27 13:27:59 +00:00
James Holderness
09d0ac768a Add an enum-compatible bitset class. (#10492)
## Summary of the Pull Request

This introduces a new TIL class that is equivalent in functionality to a `std::bitset`, but where the positions in the bitset are enum values. It also has a few additional methods allowing for setting and testing multiple positions at the same time. The idea is that this class could be used in place of the `WI_SetFlag` and `WI_IsFlagSet` macros when working with sets of flags.

## PR Checklist
* [x] Closes #10432
* [x] CLA signed.
* [x] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. Issue number where discussion took place: #10432

## Validation Steps Performed

I've added a few unit tests that verify the behaviour of all the new methods that aren't part of `std::bitset`. I've also tried it out as a replacement for the `GridLines` enum used in the renderer, and confirmed that it has all the functionality needed to replace that cleanly.
2021-09-27 13:27:29 +00:00
Leonard Hecker
2be394f421 Fix layering of fragment profiles (#11325)
This commit fixes layering of fragment profiles without an update key.
The previous CascadiaSettings deserializer first assembled all builtin
profiles and only then parsed the user's settings.json file.
This meant that even though fragment profiles were added to `_allProfiles`
unconditionally, they did get layered properly with user profiles regardless,
as user profiles were always properly layered.

The new CascadiaSettings approach since 168d28b was a direct translation of this
approach but this is incorrect: As the new approach reads user profiles first,
all inbox profiles, including fragments, must equally use proper layering,
instead of adding profiles unconditionally.

While this commit fixes the bug it maintains a regression:
Duplicate fragment profile GUIDs will not be detected and instead fragments with
identical GUID will all be added as parents to a single user profile.
I considered to fix this regression, but felt that this new behavior is better
than the old one, since a user often can't directly control installed fragments,
and is unlikely to occur in practice. This simplifies the implementation.

## PR Checklist
* [x] Closes #11323
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Fragment layering works ✔️
2021-09-24 16:21:27 +00:00
Ian O'Neill
9708a75131 Properly escape constructed wt command-lines (#11314)
Ensures that command-lines constructed to invoke `wt` are escaped properly.

## PR Checklist
* [x] Closes #11273
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed

## Detailed Description of the Pull Request / Additional comments
This was broken in two places - when constructing the command-line in the shell extension and in `NewTerminalArgs::ToCommandline()`.

Both places now invoke a shared method to escape the command-line arguments that require it.

## Validation Steps Performed
Added a test and additionally:
* Invoked the shell extension from `D:\Downloads\With;Semicolon`.
* Added a `newWindow` action to `settings.json` as below and ensured the new window opened without erroring.
  ```json
  {
    "command": 
    {
      "action": "newWindow",
      "tabTitle": "\";foo\\"
    },
    "keys": "ctrl+shift+s"
  }
  ```
2021-09-24 16:17:16 +00:00
Carlos Zamora
0f122ca290 [a11y] Ensure buffer is initialized before interacting with it (#11312)
Adds a check before every UIA function call to ensure the terminal (specifically the buffer) is initialized before doing work. Both the `ScreenInfoUiaProvider` and the `UiaTextRange` are now covered.

## References
Closes #11135 
#10971 & #11042

## Detailed Description of the Pull Request / Additional comments
Originally, I tried applying this heuristic to all the `RuntimeClassInitialize` on `UiaTextRangeBase` with the philosophy of "a range pointing to an invalid buffer is invalid itself", but that caused a regression on [MSFT 33353327](https://microsoft.visualstudio.com/OS/_workitems/edit/33353327).

`IUiaData` also has `GetTextBuffer()` return a `TextBuffer&`, which cannot be checked for nullness. Instead, I decided to add a function to `IUiaData` that checks if we have a valid state. Since this is shared with Conhost and Conhost doesn't have this issue, I simply make that function say that it's always in a valid state.

## Validation Steps Performed
- [X] Narrator can detect newly created terminals
- [X] (On Windows Server 2022) Windows Terminal does not hang on launch
2021-09-23 15:14:03 -07:00
Carlos Zamora
c070be12d3 Implement Keyboard Selection (#10824)
Implements the following keyboard selection non-configurable key bindings:
- shift+arrow --> move endpoint by character
- ctrl+shift+left/right --> move endpoint by word
- shift+home/end --> move to beginning/end of line
- ctrl+shift+home/end --> move to beginning/end of buffer

This was purposefully done in the ControlCore layer to make keyboard selection an innate part of how the terminal functions (aka a shared component across terminal consumers).

## References
#715 - Keyboard Selection
#2840 - Spec

## Detailed Description of the Pull Request / Additional comment
The most relevant section is `TerminalSelection.cpp`, where we define how each movement operates. It's basically a giant embedded switch-case statement. We leverage a lot of the work done in a11y to perform the movements.

## Validation Steps Performed
- General cases:
   - test all of the key bindings added
- Corner cases:
   - `char`: wide glyph support
   - `word`: move towards, away, and across the selection pivot
   - automatically scroll viewport
   - ESC (and other key combos) are still clearing the selection properly
2021-09-23 12:24:32 -07:00
snxx
e21eba8932 .editorconfig: add utf-8 encoding (#11190)
This commit configures compliant text editors to save our code as UTF-8.
2021-09-23 18:47:07 +00:00
Dustin L. Howett
3b7049c5b7 releng: add New-TerminalStackedChangelog (#11065)
I've done this process enough times that I should have written a script
to do it a while ago. This one is rough, but the whole changelog process
is pretty rough.

This script takes multiple revision ranges and produces something that
looks like a rough untranslated changelog, with indicators for how many
of the provided ranges had the same change (deduplicated by title.)

I use a process like this to build the Stable and Preview release notes
out of a set of revision ranges.
2021-09-23 18:05:38 +00:00
Carlos Zamora
e75f848cf3 Keyboard Selection Spec (#2840)
This introduces a spec for keyboard selection. This enables the user to create and update a selection without the use of a mouse or stylus.

## References
Contributes to #715
2021-09-23 10:58:31 -07:00
Mike Griese
171e0a0242 Add shield to tab row when elevated (#11224)
## Summary of the Pull Request

Adds a visible indicator that a Terminal window is elevated. This icon can be disabled with `"showAdminShield" false` in the global settings.

## References

* spec'd in #8455 
* Also in https://github.com/microsoft/terminal/projects/5
* big picture: #5000

## PR Checklist
* [x] Closes #1939
* [x] I work here
* [n/a] Tests added/passed
* [ ] Requires documentation to be updated - yea probably

## Validation Steps Performed

![image](https://user-images.githubusercontent.com/18356694/133293009-4215e319-fbf9-4ca8-8af5-afe2fa8bb62d.png)

![image](https://user-images.githubusercontent.com/18356694/133292970-90cb17fd-16c7-429a-a25f-8457850eb278.png)
2021-09-23 17:44:20 +00:00
PankajBhojwani
f04fd089fe Fix mouse coordinates when viewport is scrolled for all events, not just pressed (#11290)
Does the mouse coordinate adjustment added in #10642 for all the other mouse events as well (moved, released, wheel)

Closes #10190
2021-09-22 19:41:01 +00:00
Leonard Hecker
86ba1fc6c3 Fix KeyChord constructor assertion failure during tab dragging (#11306)
For some weird reason we sometimes receive a WM_KEYDOWN
message without vkey or scanCode if a user drags a tab.
The KeyChord constructor has a debug assertion ensuring that all KeyChord
either have a valid vkey/scanCode. This is important, because this prevents
accidential insertion of invalid KeyChords into classes like ActionMap.

## PR Checklist
* [x] Closes #11076
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Tab dragging doesn't produce assertion failures anymore ✔️
2021-09-22 19:39:34 +00:00
Ikko Ashimine
3afcd575df Fix typo in charsets.hpp (#11300) 2021-09-22 14:36:43 -05:00
Carlos Zamora
5deb332607 Fix UIA Word movement tests (#11253)
## Summary of the Pull Request
Fixes the 24 failing generated tests. 20 of them were fixed by enforcing the following rule: when moving backwards by word...
- a degenerate range moves to the beginning of the word, then to the word behind it.
- a non-degenerate range outright moves to the word behind it.

The fix was simple: if we're a degenerate range, check if we're at the beginning of the word. If not, move there. Otherwise, move to the word before it. See UiaTextRangeBase.cpp changes for implementation details.

Along the way, several misauthored tests were found:
- 2 generated tests:
   - Cause: MS Word considers a line break a word delimiter. We don't use line-wrapping to distinguish two separate words.
- `MovementAtExclusiveEnd` backwards word movement tests:
   - `end` will always be `writeTarget` because...
      - [degenerate range case] both `start` and `end` are moved to the beginning of the word (`writeTarget`)
      - [non-degenerate range case] from the `UiaTextRangeBase` bugfix, we should be moving to the word behind it.
   - this misauthored test was explicitly found by fixing the bug first explained here.

## References
#10925 Word navigation testing
2021-09-22 17:50:34 +00:00
Leonard Hecker
168d28b036 Reduce usage of Json::Value throughout Terminal.Settings.Model (#11184)
This commit reduces the code surface that interacts with raw JSON data,
reducing code complexity and improving maintainability.
Files that needed to be changed drastically were additionally
cleaned up to remove any code cruft that has accrued over time.

In order to facility this the following changes were made:
* Move JSON handling from `CascadiaSettings` into `SettingsLoader`
  This allows us to use STL containers for data model instances.
  For instance profiles are now added to a hashmap for O(1) lookup.
* JSON parsing within `SettingsLoader` doesn't differentiate between user,
  inbox and fragment JSON data, reducing code complexity and size.
  It also centralizes common concerns, like profile deduplication and
  ensuring that all profiles are assigned a GUID.
* Direct JSON modification, like the insertion of dynamic profiles into
  settings.json were removed. This vastly reduces code complexity,
  but unfortunately removes support for comments in JSON on first start.
* `ColorScheme`s cannot be layered. As such its `LayerJson` API was replaced
  with `FromJson`, allowing us to remove JSON-based color scheme validation.
* `Profile`s used to test their wish to layer using `ShouldBeLayered`, which
  was replaced with a GUID-based hashmap lookup on previously parsed profiles.

Further changes were made as improvements upon the previous changes:
* Compact the JSON files embedded binary, saving 28kB
* Prevent double-initialization of the color table in `ColorScheme`
* Making `til::color` getters `constexpr`, allow better optimizations

The result is a reduction of:
* 48kB binary size for the Settings.Model.dll
* 5-10% startup duration
* 26% code for the `CascadiaSettings` class
* 1% overall code in this project

Furthermore this results in the following breaking changes:
* The long deprecated "globals" settings object will not be detected and no
  warning will be created during load.
* The initial creation of a new settings.json will not produce helpful comments.

Both cases are caused by the removal of manual JSON handling and the
move to representing the settings file with model objects instead

## PR Checklist
* [x] Closes #5276
* [x] Closes #7421
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Out-of-box-experience is identical to before ✔️
  (Except for the settings.json file lacking comments.)
* Existing user settings load correctly ✔️
* New WSL instances are added to user settings ✔️
* New fragments are added to user settings ✔️
* All profiles are assigned GUIDs ✔️
2021-09-22 16:27:31 +00:00
Schuyler Rosefield
591a67111e Attempt to make the monarch more thread safe. (#11189)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References
#11083 
#11143 

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
While testing the save/quit features a number of issues were found that were caused by poor synchronization on the monarch, resulting in various unexpected crashes. Because this uses std collections, and I didn't see any builtin winrt multithreaded containers I went with the somewhat heavy-handed mutex approach.

e.g. 
- https://github.com/microsoft/terminal/pull/11083#issuecomment-916218353
- https://github.com/microsoft/terminal/pull/11083#issuecomment-916220521
- https://github.com/microsoft/terminal/pull/11143/#discussion_r704738433

This also makes it so that on quit peasants don't try to become the monarch, and the monarch closes their peasant last to prevent elections from happening.

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Create many windows (hold down ctrl-shift-n) then use the quit action from peasants/the monarch to make sure everything closes properly.
2021-09-21 21:21:45 +00:00
Michael Niksa
fbd50af8af Change exit code to hex; Fix format spec (#11123)
Process exit code now shows as hex not decimal. Format specification needs length "10" not "8" because the leading '0x' generated by the # symbol counts as part of the length.

## PR Checklist
* [x] Closes annoyance at looking up process exit codes
* [x] I work here.
* [x] Checked manually

## Validation Steps Performed
- [x] Ran it, opened tab, opened another CMD tab, ran `exit <code>` and observed hex pattern
2021-09-21 15:47:17 +00:00
Sergey
3b666b9517 Fix selection render on paste (#11286)
## Summary of the Pull Request
Clears selection render on paste

## PR Checklist
* [x] Closes #11227
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA

## Detailed Description of the Pull Request / Additional comments
Added ```_renderer->TriggerSelection(); ``` similarly to the copy action few lines up in ```CopySelectionToClipboard``` function

## Validation Steps Performed
Manually tested
2021-09-21 04:13:46 +00:00
Mike Griese
cfe14e8711 Update to MUX 2.7 (#11240)
* this is the same thing as #10996, but with the fix that caused us to #11031  
* This includes https://github.com/microsoft/microsoft-ui-xaml/pull/3769, so we had to make some adjustments to how we handle tab colors. It works the same as before.
* Should enable #11231 to be started
* [x] Closes #10508
* [x] Closes #7133
* [x] Closes #8948
* [ ] I need to finish letting my 19H1 VM boot to make sure unpackaged still works
2021-09-20 22:08:55 +00:00
Mike Griese
74f11b8203 Enable Vintage Opacity (#11180)
## Summary of the Pull Request
![603-final](https://user-images.githubusercontent.com/18356694/132585665-afed3210-257a-4fee-9b43-4273a0f5cf69.gif)

Adds support for vintage style opacity, on Windows 11+. The API we're using for this exists since the time immemorial, but there's a bug in XAML Islands that prevents it from working right until Windows 11 (which we're working on backporting).

Replaces the `acrylicOpacity` setting with `opacity`, which is a uint between 0 and 100 (inclusive), default to 100.

`useAcrylic` now controls whether acrylic is used or not. Setting an opacity < 100 with `"useAcrylic": false` will use vintage style opacity.

Mouse wheeling adjusts opacity. Whether acrylic is used or not is dependent upon `useAcrylic`.

`opacity` will stealthily default to 50 if `useAcrylic:true` is set.

## PR Checklist
* [x] Closes #603
* [x] I work here
* [x] Tests added/passed
* [x] https://github.com/MicrosoftDocs/terminal/pull/416

## Detailed Description of the Pull Request / Additional comments

Opacity was moved to AppearanceConfig. In the future, I have a mind to allow unfocused acrylic, so that'll be important then. 

## Validation Steps Performed
_just look at it_
2021-09-20 17:08:13 +00:00
Michael Niksa
0a7310dee4 Adjust tools version for folks running on 2022 (#11266)
Adjust tools version for folks running on 2022

## PR Checklist
* [x] Closes annoyance that @lhecker and I have selfhosting VS2022
* [x] I work here
* [x] Solution built
* [x] @dhowett said something like "lol sure" in Teams.
2021-09-17 20:58:08 +00:00
Carlos Zamora
d08afc4e88 [A11y] Treat last character as 'end of buffer' (#11122)
## Summary of the Pull Request
Updates our `UiaTextRange` to no longer treat the end of the buffer as the "document end". Instead, we consider the "document end" to be the line beneath the cursor or last legible character (whichever is further down). In the event where the last legible character is on the last line of the buffer, we use the "end exclusive" position (left-most point on a line one past the end of the buffer). 

When movement of any kind occurs, we clamp each endpoint to the document end. Since the document end is an actual spot in the buffer (most of the time), this should improve stability because we shouldn't be pointing out-of-bounds anymore.

The biggest benefit is that this significantly improves the performance of word navigation because screen readers no longer have to take into account the whitespace following the end of the prompt.

Word navigation tests were added to the `TestTableWriter` (see #10886). 24 of the 85 tests were failing, however, they don't seem to interact with the document end, so I've marked them as skip and will fix them in a follow-up. This PR is large enough as-is, so I'm hoping I can take time in the follow-up to clean some things on the side (aka `preventBoundary` and `allowBottomExclusive` being used interchangeably).

## References
#7000 - Epic
Closes #6986 
Closes #10925

## Validation Steps Performed
- [X] Tests pass
- [X] @codeofdusk has been personally testing this build (and others)
2021-09-16 20:44:29 +00:00
Mike Griese
4793541c90 Allow reordering tabs when UAC is disabled (#11221)
When we're elevated, we disable drag/dropping tabs when elevated, because of a platform limitation that causes the app to _crash_ (see #4874). However, if the user has UAC disabled, this actually works alright. So I'm adding it back in that case.

I'm not positive if this is the best way to check if UAC is disabled, but normally, you'll get a [`TokenElevationTypeFull`] when elevated, not `TokenElevationTypeDefault`. If the app is elevated, but there's not a split token, that kinda implies there's no user account separation. If I'm wrong, it's just code, let's replace this with something that does work.

## Validation Steps Performed

Booted up a Win10 VM, set `enableLUA` to `0`, rebooted, and checked if this exploded. It didn't.

References #4874 
References #3581
Work done in pursuit of #11096
Closes #7754

[`TokenElevationTypeFull`]: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_elevation_type
2021-09-16 17:13:10 +00:00
Ben Constable
fcb42b262f Bind resetFontSize to numpad_0 (#11243)
We already had resetFontSize bound to ctrl+0. As discussed in
#11239 it should be possible to do the same with ctrl+numpad_0.

## PR Checklist
* [x] Closes #11239
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: https://github.com/MicrosoftDocs/terminal/pull/412

## Validation Steps Performed

* Resetting the font size with ctrl+numpad_0 works
2021-09-16 07:14:15 +00:00
Dustin L. Howett
6983ecf1ba VsSetup: Replace com_ptr params with raw pointers, clean up code (#11242)
This commit aligns the COM-consuming code in VsSetupInstance with best
practices such as passing COM pointers by pointer when they do not need
to be owning references and not using `const` on members, as well as
cleans up some dead code.

Leonard contributed clang-tidy fixes and some reference passing
changes.

Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
2021-09-16 00:41:49 +00:00
Charles Willis
f84da18d1e Add profile generators for Visual Studio (#7774)
This commit adds dynamic profile generators for Visual Studio Developer
Command Prompt (VS2017+) and Visual Studio Developer PowerShell
(VS2019.2+)

Tested manually by deploying locally. My local environment has four
instances of VS installed, one VS2017 and multiple channels of VS2019.

We're wrapping the COM Visual Studio Setup Configuration API to query
for VS instances and retrieve the relevant properties.  Two different
namespaces are used so the end-user can turn off one or the other. For
instance, end user may prefer to always use Developer PowerShell. 

## Validation Steps Performed
1. Build locally using Visual Studio 2019
2. Deploy CascadiaPackage
3. Verify entries exist in profiles menu
4. Verify entries exist in settings.json
5. Open each profile
6. Validate start-in directory
7. Validate environment variables are as expected
8. Uninstall Windows Terminal - Dev package
9. Repeat.

Closes #3821
2021-09-15 17:20:06 -05:00
Schuyler Rosefield
87b695f826 Add the ability to split a pane and put the new pane first. (#11145)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane.

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #4340
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
"vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`.

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Split the pane using each of the new directional movements
2021-09-15 20:14:57 +00:00
Ian O'Neill
121116ceb3 Fix serialisation of findMatch action (#11233)
## Summary of the Pull Request
Fixes the serialisation of the findMatch action so that the direction is stored.

## PR Checklist
* [x] Closes #11225
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
Added a test and tested manually.
2021-09-15 18:00:33 +00:00
Leon Liang
844d46a132 Replace TrayIcon with NotificationIcon (#11219)
This PR simply replaces all uses of "TrayIcon" and "Tray" with "NotificationIcon" and "NotificationArea" to be more accurate. Originally I kinda wanted to only replace all occurrences of it in settings and user facing things, but I figured I might as well make it consistent throughout all of our code.
2021-09-14 16:12:40 +00:00
Schuyler Rosefield
b4a40ff11e Make sure we fully clean up state when closing a peasant (#11217)
Fix infinite loop when trying to summon a window after close.

In #10972 code was added to try to clean up state manually when a window
was closed instead of waiting for it to be detected as a dead peasant.
Unfortunately I didn't know any better and missed cleaning up
`_mruPeasants` as well. The result is there  would be an infinite loop
in `_getMostRecentPeasant` since `_getPeasant` will only clean up ids if
it finds a peasant, not if it doesn't find anything. This is the minimal
change to get this working, but it might be a good idea to make
`_getPeasant` be more thorough about cleanup.

## Validation Steps Performed
Tested that before the change we infinitely loop, and after the change
we summon correctly.

Closes #11215
2021-09-14 14:53:14 +00:00
Dustin L. Howett
3d7480e9b7 Upgrade to C++/WinRT 2.0.210825.3 (#11188)
This pull request moves us to Microsoft.Windows.CppWinRT 2.0.210825.3.

Notable improvements from 2.0.210309.3:
* Restored Windows 7 functionality
* C++20 ranges support
* `capture` now works with a raw pointer
* `hstring::starts_with` and `hstring::ends_with` (C++20)

Unit/Functional Tests:
Summary: Total=7728, Passed=7571, Failed=10, Blocked=0, Not Run=0, Skipped=147

Local Tests:
Summary: Total=163, Passed=158, Failed=5, Blocked=0, Not Run=0, Skipped=0

The above failures are (1) in UIA tests for conhost/WT (which do not work here) or
(2) in already known-broken local tests.
2021-09-10 21:33:13 +00:00
PankajBhojwani
97722d3efe Add an openSystemMenu keybinding (#11086)
## Summary of the Pull Request
Basically undoes #10988  in favour of implementing it as described in #11018 

## PR Checklist
* [x] Closes #11018 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [X] Tests added/passed
* [X] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [X] Schema updated.
* [x] I work here

## Validation Steps Performed

- alt+space opens the system menu by default
- when alt+space is bound, the keys do not get send to terminal
- right-click on the tab bar didn't break (still opens system menu at the location of the cursor)
2021-09-10 18:25:43 +00:00
Don-Vito
a900ababdc Teach info bars to be dismissed permanently (#11139)
## Summary of the Pull Request
* Introduces info bar shown upon session failure, 
that guides the user how to configure termination behavior
  * Allows this info bar to be dismissed permanently (choice stored in state) 
* Allows "keyboard service" info bar to be dismissed permanently

## PR Checklist
* [x] Closes #10798, #8699
* [x] CLA signed. 
* [ ] Tests added/passed
* [ ] Documentation updated. 
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already.

## Detailed Description of the Pull Request / Additional comments
UI:
* Introduce an additional info bar for "close on exit" configuration tip
  * Stack this bar after "keyboard service" bar
* Add "Don't show again" button to both bars

Dismiss Permanently:
* Introduce a set of "dismissed messages" to the Application State
* Add verification the message is not dismissed before showing an info bar
* "Don't show  again" persists the choice under "dismissed messages"

Wiring the Info Bar:
* Register `TerminalPage` on `TermControl`'s `ConnectionStateChanged` event
* Once event is triggered check whether the state is failure
* If so and the message was not dismissed permanently, show the info bar
2021-09-10 17:16:41 +00:00
gabrielconl
54ed295588 Search box visual tweaks (#11105)
Made some changes to the search box:
* Adjusted spacing inside the box
* Detached the search box from the titlebar (as explained [here](https://github.com/microsoft/terminal/issues/1375#issuecomment-856667292))
* The search box is now 8px further to the left, in case the scrollbar is always enabled
* Made some controls use default properties, so that they'll adjust nicely to the 2.6 styles

Other: the search box and command palette now use OverlayCornerRadius

Before/After:
![image](https://user-images.githubusercontent.com/84711285/131888377-513b9de4-a653-4086-9a67-8718c64dc75b.png)
2021-09-09 18:00:46 +00:00
Schuyler Rosefield
bee6fb4368 Add the ability to quit all terminal instances (#11143)
Add the ability to quit all terminal instances. Doing this separately from the window layout saving ones to lessen the number of 1k+ line monsters I make y'all review.

## References
#11083 

## PR Checklist
* [x] Closes #11081
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.

## Detailed Description of the Pull Request / Additional comments
- Warn the user before they do so to give a chance to cancel
- Percolate a QuitAll event up to the monarch who then directs each peasant to clsoe.
- Leave a window-layout-saving-sized hole to add that feature on top

## Validation Steps Performed
- quit with one window (from the monarch)
- quit from the monarch with multiple windows
- quit from a peasant
- cancel the quit dialog

![image](https://user-images.githubusercontent.com/6185249/132105775-3310f614-ce55-4454-9718-ef5c0d39fbd2.png)
2021-09-09 14:03:03 +00:00
James Holderness
6140fd9ab8 Add basic support for the DECRQSS settings query (#11152)
This PR adds support for the `DECRQSS` (Request Selection or Setting)
escape sequence, which is a standard VT query for reporting the state of
various control functions. This initial implementation only supports
queries for the `DECSTBM` margins, and the `SGR` graphic rendition
attributes.

This can be useful for certain forms of capability detection (#1040). As
one example in particular, it can serve as an alternative to the
`COLORTERM` environment variable for detecting truecolor support
(#11057). 

Of the settings that can be queried by `DECRQSS`, the only other one
that we could be supporting at the moment is `DECSCUSR` (Cursor Style).
However, that would require passing the query through to the conpty
client, which is a lot more complicated, so I thought it best to leave
for a future PR.

For now this gets the basic framework in place, so we are at least
responding to queries, and even just supporting the `SGR` attributes
query is useful in itself.

Validation
----------
I've added a unit test verifying the reports for the `DECSTBM` and `SGR`
settings with a range of different parameters. I've also tested the
`DECSTBM` and `SGR` reports manually in _Vttest_, under menu 11.2.5.3.6
(Status-String Reports).
2021-09-08 23:26:44 +00:00
Schuyler Rosefield
13e9546bab Persist window layout on window close (#10972)
This commit adds initial support for saving window layout on application
close.

Done:
- Add user setting for if tabs should be maintained.
- Added events to track the number of open windows for the monarch, and
  then save if you are the last window closing.
- Saves layout when the user explicitly hits the "Close Window" button.
- If the user manually closed all of their tabs (through the tab x
  button or through closing all panes on the tab) then remove any saved
  state.
- Saves in the ApplicationState file a list of actions the terminal can
  perform to restore its layout and the window size/position
  information.
- This saves an action to focus the correct pane, but this won't
  actually work without #10978. Note that if you have a pane zoomed, it
  does still zoom the correct pane, but when you unzoom it will have a
  different pane selected.

Todo:
- multiple windows? Right now it can only handle loading/saving one
  window.
   - PR #11083 will save multiple windows.
- This also sometimes runs into the existing bug where multiple tabs
  appear to be focused on opening.

Next Steps:
- The business logic of when the save is triggered can be adjusted as
  necessary.
- Right now I am taking the pragmatic approach and just saving the state
  as an array of objects, but only ever populate it with 1, that way
  saving multiple windows in the future could be added without breaking
  schema compatibility. Selfishly I'm hoping that handling multiple
  windows could be spun off into another pr/feature for now.
- One possible thing that can maybe be done is that the commandline can
  be augmented with a "--saved ##" attribute that would load from the
  nth saved state if it exists. e.g. if there are 3 saved windows, on
  first load it can spawn three wt --saved {0,1,2} that would reopen the
  windows? This way there also exists a way to load a copy of a previous
  window (if it is in the saved state).
- Is the application state something that is planned to be public/user
  editable? In theory the user could since it is just json, but I don't
  know what it buys them over just modifying their settings and
  startupActions.

Validation Steps Performed:
- The happy path: open terminal -> set setting to true -> close terminal
  -> reopen and see tabs. Tested with powershell/cmd/wsl windows.
- That closing all panes/tabs on their own will remove the saved
  session.
- Open multiple windows, close windows and confirm that the last window
  closed saves its state.

The generated file stores a sequence of actions that will be executed to
restore the terminal to its saved form.

References #8324
This is also one of the items on microsoft/terminal#5000
Closes #766
2021-09-08 22:44:53 +00:00
Schuyler Rosefield
0a48836e83 Fix tab movement while running multiple actions (#11144)
## Summary of the Pull Request
Make sure to always synchronously set the selected tab. This way when changing tabs while running multiple actions further calls to _GetFocusedTab will return the correct one.

**Edit** #11146  discovered while trying to test this so while I fixed the case I wanted, things seem to be broken generally so it is hard for me to test if I broke anything else.

## References

## PR Checklist
* [x] Closes #11107 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA

## Validation Steps Performed
Ran the command specified in the issue and confirmed that the correct tab was focused and that the correct pane was zoomed.
2021-09-07 13:34:48 -07:00
Ian O'Neill
43c76ee240 Disable autocorrect for command, path and find text inputs (#11137)
## Summary of the Pull Request
Disables autocorrect for command, path and find text inputs. Does not disable it for profile names, tab titles or colour scheme names.

## PR Checklist
* [x] Closes #11133
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA

## Validation Steps Performed
Manually typed `bash -i -l` into the profile command text input and found it no longer auto-capitalised the I.
2021-09-07 10:53:53 -07:00
Leon Liang
424414ec97 Provide the focused tab title in the Tray Icon's context menu (#11043)
This PR adds a bit more information to each item in the Tray Icon's  window selection submenu. 
Currently it only shows the window ID and window name if given one. 
Now each item will instead show`{Window ID} : {Active Tab Title} [{Window Name}]`

![image](https://user-images.githubusercontent.com/57155886/130883675-7a76e674-2429-4b26-b869-2455a9e4b4f6.png)
2021-09-03 18:32:23 +00:00
489 changed files with 23494 additions and 12863 deletions

View File

@@ -1,6 +1,7 @@
root = true
[*]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

2
.gitattributes vendored
View File

@@ -3,6 +3,8 @@
###############################################################################
* -text
*.inc linguist-language=cpp
###############################################################################
# Set default behavior for command prompt diff.
#

15
.github/actions/spelling/README.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# check-spelling/check-spelling configuration
File | Purpose | Format | Info
-|-|-|-
[allow/*.txt](allow/) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow)
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
[patterns/*.txt](patterns/) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[expect/*.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
Note: you can replace any of these files with a directory by the same name (minus the suffix)
and then include multiple files inside that directory (with that suffix) to merge multiple files together.

View File

@@ -1,4 +1,4 @@
<!-- markdownlint-disable MD033 MD041 -->
<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details>
<summary>
:pencil2: Contributor please read this
@@ -6,7 +6,7 @@
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
:warning: The command is written for posix shells. You can copy the contents of each `perl` command excluding the outer `'` marks and dropping any `'"`/`"'` quotation mark pairs into a file and then run `perl file.pl` from the root of the repository to run the code. Alternatively, you can manually insert the items...
:warning: The command is written for posix shells. If it doesn't work for you, you can manually _add_ (one word per line) / _remove_ items to `expect.txt` and the `excludes.txt` files.
If the listed items are:
@@ -20,31 +20,29 @@ See the `README.md` in each directory for more information.
:microscope: You can test your commits **without** *appending* to a PR by creating a new branch with that extra change and pushing it to your fork. The [check-spelling](https://github.com/marketplace/actions/check-spelling) action will run in response to your **push** -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. :wink:
<details><summary>:clamp: If you see a bunch of garbage</summary>
If it relates to a ...
<details><summary>well-formed pattern</summary>
<details><summary>If the flagged items are :exploding_head: false positives</summary>
See if there's a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it.
If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).
If not, try writing one and adding it to a `patterns/{file}.txt`.
Please add a file path to the `excludes.txt` file matching the containing file.
Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
</details>
<details><summary>binary-ish string</summary>
Please add a file path to the `excludes.txt` file instead of just accepting the garbage.
File paths are Perl 5 Regular Expressions - you can [test](
File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).
</details>
* well-formed pattern.
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
try adding it to the `patterns.txt` file.
Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
</details>
</details>

View File

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

View File

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

View File

@@ -1,3 +1,11 @@
atan
CPrime
HBar
HPrime
isnan
LPrime
LStep
powf
RSub
sqrtf
ULP

View File

@@ -1,5 +1,6 @@
ACLs
ADMINS
advapi
altform
altforms
appendwttlogging
@@ -15,8 +16,10 @@ CPLs
cpptools
cppvsdbg
CPRs
cryptbase
DACL
DACLs
defaultlib
diffs
disposables
dotnetfeed
@@ -24,7 +27,11 @@ DTDs
DWINRT
enablewttlogging
Intelli
IVisual
libucrt
libucrtd
LKG
LOCKFILE
Lxss
mfcribbon
microsoft
@@ -32,8 +39,10 @@ microsoftonline
MSAA
msixbundle
MSVC
MSVCP
muxc
netcore
Onefuzz
osgvsowi
PFILETIME
pgc
@@ -44,6 +53,7 @@ powershell
propkey
pscustomobject
QWORD
regedit
robocopy
SACLs
sdkddkver
@@ -57,6 +67,8 @@ systemroot
taskkill
tasklist
tdbuildteamid
ucrt
ucrtd
unvirtualized
VCRT
vcruntime

View File

@@ -1,14 +1,18 @@
Anup
austdi
arkthur
Ballmer
bhoj
Bhojwani
Bluloco
carlos
dhowett
Diviness
dsafa
duhowett
DXP
ekg
eryksun
ethanschoonover
Firefox
Gatta
@@ -20,6 +24,7 @@ Hernan
Howett
Illhardt
iquilezles
italo
jantari
jerrysh
Kaiyu
@@ -33,7 +38,9 @@ leonmsft
Lepilleur
lhecker
lukesampson
Macbook
Manandhar
masserano
mbadolato
Mehrain
menger
@@ -53,6 +60,7 @@ oldnewthing
opengl
osgwiki
pabhojwa
panos
paulcam
pauldotknopf
PGP
@@ -61,12 +69,16 @@ Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Walisch
WDX
Wellons
Wirt
Wojciech

View File

@@ -0,0 +1,523 @@
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
# marker for ignoring a comment to the end of the line
// #no-spell-check.*$
# patch hunk comments
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
# git index header
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# cid urls
(['"])cid:.*?\g{-1}
# data url in parens
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
# data url in quotes
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# data url
data:[-a-zA-Z=;:/0-9+]*,\S*
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# magnet urls
magnet:[?=:\w]+
# magnet urls
"magnet:[^"]+"
# obs:
"obs:[^"]*"
# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read
# In this examples content, I'm using a number of different ways to match things to show various approaches
# asciinema
\basciinema\.org/a/[0-9a-zA-Z]+
# apple
\bdeveloper\.apple\.com/[-\w?=/]+
# Apple music
\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+
# appveyor api
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
# appveyor project
\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+
# Amazon
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
# AWS S3
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
# AWS execute-api
\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b
# AWS ELB
\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b
# AWS SNS
\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]*
# AWS VPC
vpc-\w+
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
# YouTube music
\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*)
# YouTube tag
<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"]
# YouTube image
\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]*
# Google Accounts
\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]*
# Google Analytics
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
# Google APIs
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
# Google Storage
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
# Google Calendar
\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+
\w+\@group\.calendar\.google\.com\b
# Google DataStudio
\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|)
# The leading `/` here is as opposed to the `\b` above
# ... a short way to match `https://` or `http://` since most urls have one of those prefixes
# Google Docs
/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|))
# Google Drive
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
# Google Groups
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)*
# Google Maps
\bmaps\.google\.com/maps\?[\w&;=]*
# Google themes
themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
# Google CDN
\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]*
# Goo.gl
/goo\.gl/[a-zA-Z0-9]+
# Google Chrome Store
\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|)
# Google Books
\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]*
# Google Fonts
\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]*
# Google Forms
\bforms\.gle/\w+
# Google Scholar
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
# Google Colab Research Drive
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
# GitHub SHAs (api)
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
# GitHub SHAs (markdown)
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# GitHub SHAs
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
# GitHub wiki
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
# githubusercontent
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
# githubassets
\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+)
# gist github
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
# git.io
\bgit\.io/[0-9a-zA-Z]+
# GitHub JSON
"node_id": "[-a-zA-Z=;:/0-9+]*"
# Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
# GHSA
GHSA(?:-[0-9a-z]{4}){3}
# GitLab commit
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
# GitLab merge requests
\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b
# GitLab uploads
\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]*
# GitLab commits
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
# binanace
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
# bitbucket diff
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
# bitbucket repositories commits
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
# bitbucket commits
\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
# bit.ly
\bbit\.ly/\w+
# bitrise
\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]*
# bootstrapcdn.com
\bbootstrapcdn\.com/[-./\w]+
# cdn.cloudflare.com
\bcdnjs\.cloudflare\.com/[./\w]+
# circleci
\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+
# gitter
\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+
# gravatar
\bgravatar\.com/avatar/[0-9a-f]+
# ibm
[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]*
# imgur
\bimgur\.com/[^.]+
# Internet Archive
\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*)
# discord
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
# Disqus
\bdisqus\.com/[-\w/%.()!?&=_]*
# medium link
\blink\.medium\.com/[a-zA-Z0-9]+
# medium
\bmedium\.com/\@?[^/\s"]+/[-\w]+
# microsoft
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
# powerbi
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
# vs devops
\bvisualstudio.com(?::443|)/[-\w/?=%&.]*
# microsoft store
\bmicrosoft\.com/store/apps/\w+
# mvnrepository.com
\bmvnrepository\.com/[-0-9a-z./]+
# now.sh
/[0-9a-z-.]+\.now\.sh\b
# oracle
\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]*
# chromatic.com
/\S+.chromatic.com\S*[")]
# codacy
\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+
# compai
\bcompai\.pub/v1/png/[0-9a-f]+
# mailgun api
\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]*
# mailgun
\b[0-9a-z]+.mailgun.org
# /message-id/
/message-id/[-\w@./%]+
# Reddit
\breddit\.com/r/[/\w_]*
# requestb.in
\brequestb\.in/[0-9a-z]+
# sched
\b[a-z0-9]+\.sched\.com\b
# Slack url
slack://[a-zA-Z0-9?&=]+
# Slack
\bslack\.com/[-0-9a-zA-Z/_~?&=.]*
# Slack edge
\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+
# Slack images
\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+
# shields.io
\bshields\.io/[-\w/%?=&.:+;,]*
# stackexchange -- https://stackexchange.com/feeds/sites
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
# Sentry
[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b
# Twitter markdown
\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\)
# Twitter hashtag
\btwitter\.com/hashtag/[\w?_=&]*
# Twitter status
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
# Twitter profile images
\btwimg\.com/profile_images/[_\w./]*
# Twitter media
\btwimg\.com/media/[-_\w./?=]*
# Twitter link shortened
\bt\.co/\w+
# facebook
\bfburl\.com/[0-9a-z_]+
# facebook CDN
\bfbcdn\.net/[\w/.,]*
# facebook watch
\bfb\.watch/[0-9A-Za-z]+
# dropbox
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
# ipfs protocol
ipfs://[0-9a-z]*
# ipfs url
/ipfs/[0-9a-z]*
# w3
\bw3\.org/[-0-9a-zA-Z/#.]+
# loom
\bloom\.com/embed/[0-9a-f]+
# regex101
\bregex101\.com/r/[^/\s"]+/\d+
# figma
\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+
# freecodecamp.org
\bfreecodecamp\.org/[-\w/.]+
# image.tmdb.org
\bimage\.tmdb\.org/[/\w.]+
# mermaid
\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+
# Wikipedia
\ben\.wikipedia\.org/wiki/[-\w%.#]+
# gitweb
[^"\s]+/gitweb/\S+;h=[0-9a-f]+
# HyperKitty lists
/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/
# lists
/thread\.html/[^"\s]+
# list-management
\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+
# kubectl.kubernetes.io/last-applied-configuration
"kubectl.kubernetes.io/last-applied-configuration": ".*"
# pgp
\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]*
# Spotify
\bopen\.spotify\.com/embed/playlist/\w+
# Mastodon
\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]*
# scastie
\bscastie\.scala-lang\.org/[^/]+/\w+
# images.unsplash.com
\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+
# pastebin
\bpastebin\.com/[\w/]+
# heroku
\b\w+\.heroku\.com/source/archive/\w+
# quip
\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)?
# badgen.net
\bbadgen\.net/badge/[^")\]'\s]+
# statuspage.io
\w+\.statuspage\.io\b
# media.giphy.com
\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+
# tinyurl
\btinyurl\.com/\w+
# getopts
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# URL escaped characters
\%[0-9A-F][A-F]
# IPv6
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
# c99 hex digits (not the full format, just one I've seen)
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
# Punycode
\bxn--[-0-9a-z]+
# sha
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture
(['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
# hex in url queries
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
# ssh
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
# PGP
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
# GPG keys
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
# Well known gpg keys
.well-known/openpgpkey/[\w./]+
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# integrity
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
# https://www.gnu.org/software/groff/manual/groff.html
# man troff content
\\f[BCIPR]
# '
\\\(aq
# .desktop mime types
^MimeTypes?=.*$
# .desktop localized entries
^[A-Z][a-z]+\[[a-z]+\]=.*$
# Localized .desktop content
Name\[[^\]]+\]=.*
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# crypt
"\$2[ayb]\$.{56}"
# scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+
# Input to GitHub JSON
content: "[-a-zA-Z=;:/0-9+]*="
# Python stringprefix / binaryprefix
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+
# JavaScript regular expressions
# javascript test regex
/.*/[gim]*\.test\(
# javascript match regex
\.match\(/[^/\s"]*/[gim]*\s*
# javascript match regex
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
# javascript regex
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
# javascript replace regex
\.replace\(/[^/\s"]*/[gim]*\s*,
# Go regular expressions
regexp?\.MustCompile\(`[^`]*`\)
# sed regular expressions
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
# go install
go install(?:\s+[a-z]+\.[-@\w/.]+)+
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
# kubectl - pods in CrashLoopBackOff
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
# kubernetes object suffix
-[0-9a-f]{10}-\w{5}\s
# posthog secrets
posthog\.init\((['"])phc_[^"',]+\g{-1},
# xcode
# xcodeproject scenes
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches
customObjectInstantitationMethod
# font awesome classes
\.fa-[-a-z0-9]+
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
## You could manually change `(?i)X...` to use `[Xx]...`
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
# Lorem
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# French
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
# Note that the next example is no longer necessary if you are using
# to match a string starting with a `#`, use a character-class:
[#]backwards
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# Compiler flags (Scala)
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (linker)
,-B
# curl arguments
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# macOS temp folders
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/

View File

@@ -1,28 +1,39 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
(?:(?i)\.png$)
(?:^|/)(?i)COPYRIGHT
(?:^|/)(?i)LICEN[CS]E
(?:^|/)3rdparty/
(?:^|/)dirs$
(?:^|/)go\.mod$
(?:^|/)go\.sum$
(?:^|/)package-lock\.json$
(?:^|/)package(?:-lock|)\.json$
(?:^|/)sources(?:|\.dep)$
SUMS$
(?:^|/)vendor/
\.a$
\.ai$
\.avi$
\.bmp$
\.bz2$
\.cer$
\.class$
\.crl$
\.crt$
\.csr$
\.dll$
\.docx?$
\.drawio$
\.DS_Store$
\.eot$
\.eps$
\.exe$
\.gif$
\.gitattributes$
\.graffle$
\.gz$
\.icns$
\.ico$
\.jar$
\.jks$
\.jpeg$
\.jpg$
\.key$
@@ -30,28 +41,53 @@ SUMS$
\.lock$
\.map$
\.min\..
\.mod$
\.mp3$
\.mp4$
\.o$
\.ocf$
\.otf$
\.pbxproj$
\.pdf$
\.pem$
\.png$
\.psd$
\.pyc$
\.runsettings$
\.s$
\.sig$
\.so$
\.svg$
\.svgz$
\.svgz?$
\.tar$
\.tgz$
\.tiff?$
\.ttf$
\.vsdx$
\.wav$
\.webm$
\.webp$
\.woff
\.woff2?$
\.xcf$
\.xls
\.xlsx?$
\.xpm$
\.yml$
\.zip$
^\.github/actions/spelling/
^\.github/fabricbot.json$
^\.gitignore$
^\Q.git-blame-ignore-revs\E$
^\Q.github/workflows/spelling.yml\E$
^\Qdoc/reference/windows-terminal-logo.ans\E$
^\Qsamples/ConPTY/EchoCon/EchoCon/EchoCon.vcxproj.filters\E$
^\Qsrc/host/exe/Host.EXE.vcxproj.filters\E$
^\Qsrc/host/ft_host/chafa.txt\E$
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
^\XamlStyler.json$
^build/config/
^consolegit2gitfilters\.json$
^dep/
^doc/reference/master-sequence-list.csv$
@@ -61,12 +97,14 @@ SUMS$
^src/host/runft\.bat$
^src/host/runut\.bat$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/atlas/
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/adapter/ut_adapter/run\.bat$
^src/terminal/parser/delfuzzpayload\.bat$
^src/terminal/parser/ft_fuzzer/run\.bat$
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/terminal/parser/ft_fuzzwrapper/run\.bat$
^src/terminal/parser/ut_parser/Base64Test.cpp$
^src/terminal/parser/ut_parser/run\.bat$
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
^src/tools/lnkd/lnkd\.bat$
@@ -74,6 +112,6 @@ SUMS$
^src/tools/texttests/fira\.txt$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^src/types/ut_types/UtilsTests.cpp$
^\.github/actions/spelling/
^\.gitignore$
^\XamlStyler.json$
^tools/ReleaseEngineering/ServicingPipeline.ps1$
ignore$
SUMS$

View File

@@ -5,26 +5,19 @@ AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
abcd
abcde
abcdef
ABCDEFG
ABCDEFGH
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNO
abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
abcdefghijklmnopqrstuvwxyz
ABCG
ABE
abf
BBBBB
BBBBBBBB
BBBBBBBBBBBBBBDDDD
BBBBBCCC
BBBBCCCCC
BBGGRR
CCE
EFG
EFGh
QQQQQQQQQQABCDEFGHIJ
@@ -33,7 +26,6 @@ QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
qrstuvwxyz
qwerty
QWERTYUIOP
qwertyuiopasdfg
YYYYYYYDDDDDDDDDDD
ZAAZZ

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,62 @@
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
# \bm_data\b
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want
# to use this:
#\bfit\(
# s.b. GitHub
\bGithub\b
# s.b. GitLab
\bGitlab\b
# s.b. JavaScript
\bJavascript\b
# s.b. Microsoft
\bMicroSoft\b
# s.b. another
\ban[- ]other\b
# s.b. greater than
\bgreater then\b
# s.b. into
#\sin to\s
# s.b. opt-in
\sopt in\s
# s.b. less than
\bless then\b
# s.b. otherwise
\bother[- ]wise\b
# s.b. nonexistent
\bnon existing\b
\b[Nn]o[nt][- ]existent\b
# s.b. preexisting
[Pp]re[- ]existing
# s.b. preempt
[Pp]re[- ]empt\b
# s.b. preemptively
[Pp]re[- ]emptively
# s.b. reentrancy
[Rr]e[- ]entrancy
# s.b. reentrant
[Rr]e[- ]entrant
# s.b. workaround(s)
#\bwork[- ]arounds?\b
# Reject duplicate words
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s

View File

@@ -1,11 +1,6 @@
https://(?:(?:[-a-zA-Z0-9?&=]*\.|)microsoft\.com)/[-a-zA-Z0-9?&=_#\/.]*
https://aka\.ms/[-a-zA-Z0-9?&=\/_]*
https://www\.itscj\.ipsj\.or\.jp/iso-ir/[-0-9]+\.pdf
https://www\.vt100\.net/docs/[-a-zA-Z0-9#_\/.]*
https://www.w3.org/[-a-zA-Z0-9?&=\/_#]*
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
https://(?:[a-z-]+\.|)github(?:usercontent|)\.com/[-a-zA-Z0-9?%&=_\/.]*
https://www.xfree86.org/[-a-zA-Z0-9?&=\/_#]*
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
https?://\S+
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]{0,2}\b
@@ -24,3 +19,78 @@ VERIFY_ARE_EQUAL\(L"[^"]+"
std::memory_order_[\w]+
D2DERR_SHADER_COMPILE_FAILED
TIL_FEATURE_[0-9A-Z_]+
vcvars\w*
ROY\sG\.\sBIV
!(?:(?i)ESC)!\[
!(?:(?i)CSI)!(?:\d+(?:;\d+|)m|[ABCDF])
# Python stringprefix / binaryprefix
\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'
# Automatically suggested patterns
# hit-count: 3831 file-count: 582
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 71 file-count: 35
# Compiler flags
(?:^|[\t ,"'`=(])-[D](?=[A-Z]{2,}|[A-Z][a-z])
(?:^|[\t ,"'`=(])-[X](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# hit-count: 41 file-count: 28
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# hit-count: 20 file-count: 9
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 10 file-count: 7
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hit-count: 4 file-count: 4
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# hit-count: 4 file-count: 1
# ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# hit-count: 2 file-count: 1
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# hit-count: 1 file-count: 1
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# hit-count: 1 file-count: 1
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# hit-count: 1 file-count: 1
# French
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# acceptable duplicates
# ls directory listings
[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+
# C/idl types + English ...
\s(Guid|long|LONG|that) \g{-1}\s
# javadoc / .net
(?:[\\@](?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s
# Commit message -- Signed-off-by and friends
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$
# Autogenerated revert commit message
^This reverts commit [0-9a-f]{40}\.$
# vtmode
--vtmode\s+(\w+)\s+\g{-1}\s
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b

View File

@@ -1,22 +1,12 @@
^attache$
^attacher$
^attachers$
^spae$
^spaebook$
^spaecraft$
^spaed$
^spaedom$
^spaeing$
^spaeings$
^spae-man$
^spaeman$
^spaer$
^Spaerobee$
^spaes$
^spaewife$
^spaewoman$
^spaework$
^spaewright$
^wether$
^wethers$
^wetherteg$
benefitting
occurences?
^dependan.*
^oer$
Sorce
^[Ss]pae.*
^untill$
^untilling$
^wether.*

View File

@@ -1,20 +1,134 @@
# spelling.yml is blocked per https://github.com/check-spelling/check-spelling/security/advisories/GHSA-g86g-chm8-7r2p
name: Spell checking
# Comment management is handled through a secondary job, for details see:
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
#
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
# (in odd cases, it might actually run just to collapse a commment, but that's fairly rare)
# it needs `contents: write` in order to add a comment.
#
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment)
# it needs `pull-requests: write` in order to manipulate those comments.
# Updating pull request branches is managed via comment handling.
# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list
#
# These elements work together to make it happen:
#
# `on.issue_comment`
# This event listens to comments by users asking to update the metadata.
#
# `jobs.update`
# This job runs in response to an issue_comment and will push a new commit
# to update the spelling metadata.
#
# `with.experimental_apply_changes_via_bot`
# Tells the action to support and generate messages that enable it
# to make a commit to update the spelling metadata.
#
# `with.ssh_key`
# In order to trigger workflows when the commit is made, you can provide a
# secret (typically, a write-enabled github deploy key).
#
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
on:
pull_request_target:
push:
branches:
- "**"
tags-ignore:
- "**"
pull_request_target:
branches:
- "**"
tags-ignore:
- "**"
types:
- 'opened'
- 'reopened'
- 'synchronize'
issue_comment:
types:
- 'created'
jobs:
spelling:
name: Spell checking
permissions:
contents: read
pull-requests: read
actions: read
outputs:
followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'"
concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress
cancel-in-progress: true
steps:
- name: checkout-merge
if: "contains(github.event_name, 'pull_request')"
uses: actions/checkout@v2
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@v0.0.21
with:
ref: refs/pull/${{github.event.pull_request.number}}/merge
- name: checkout
if: "!contains(github.event_name, 'pull_request')"
uses: actions/checkout@v2
- uses: check-spelling/check-spelling@v0.0.19
suppress_push_for_open_pull_request: 1
checkout: true
check_file_names: 1
spell_check_this: check-spelling/spell-check-this@prerelease
post_comment: 0
use_magic_file: 1
extra_dictionary_limit: 10
extra_dictionaries:
cspell:software-terms/src/software-terms.txt
cspell:python/src/python/python-lib.txt
cspell:node/node.txt
cspell:cpp/src/stdlib-c.txt
cspell:cpp/src/stdlib-cpp.txt
cspell:fullstack/fullstack.txt
cspell:filetypes/filetypes.txt
cspell:html/html.txt
cspell:cpp/src/compiler-msvc.txt
cspell:python/src/common/extra.txt
cspell:powershell/powershell.txt
cspell:aws/aws.txt
cspell:cpp/src/lang-keywords.txt
cspell:npm/npm.txt
cspell:dotnet/dotnet.txt
cspell:python/src/python/python.txt
cspell:css/css.txt
cspell:cpp/src/stdlib-cmath.txt
check_extra_dictionaries: ''
comment-push:
name: Report (Push)
# If your workflow isn't running on push, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
contents: write
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}
comment-pr:
name: Report (PR)
# If you workflow isn't running on pull_request*, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}

View File

@@ -125,7 +125,7 @@ Team members will be happy to help review specs and guide them to completion.
### Help Wanted
Once the team have approved an issue/spec, development can proceed. If no developers are immediately available, the spec can be parked ready for a developer to get started. Parked specs' issues will be labeled "Help Wanted". To find a list of development opportunities waiting for developer involvement, visit the Issues and filter on [the Help-Wanted label](https://github.com/microsoft/terminal/labels/Help%20Wanted).
Once the team has approved an issue/spec, development can proceed. If no developers are immediately available, the spec can be parked ready for a developer to get started. Parked specs' issues will be labeled "Help Wanted". To find a list of development opportunities waiting for developer involvement, visit the Issues and filter on [the Help-Wanted label](https://github.com/microsoft/terminal/labels/Help%20Wanted).
---

View File

@@ -117,7 +117,6 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## dynamic_bitset
@@ -148,7 +147,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
## \{fmt\}
@@ -215,7 +213,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
@@ -249,7 +246,34 @@ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
## PCG Random Number Generation
**Source**: [https://github.com/imneme/pcg-cpp](https://github.com/imneme/pcg-cpp)
### License
```
Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
# Microsoft Open Source

View File

@@ -10,6 +10,8 @@
<clear />
</disabledPackageSources>
<config>
<!-- TODO: TEMPORARY UNTIL PGO-Helpers is updated to search both. We shouldn't need to keep the globals path here. -->
<add key="globalPackagesFolder" value=".\packages" />
<add key="repositorypath" value=".\packages" />
</config>
</configuration>

View File

@@ -268,8 +268,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererUia", "src\renderer
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinRTUtils", "src\cascadia\WinRTUtils\WinRTUtils.vcxproj", "{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminalUniversal", "src\cascadia\WindowsTerminalUniversal\WindowsTerminalUniversal.vcxproj", "{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winconpty.LIB", "src\winconpty\lib\winconptylib.vcxproj", "{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winconpty.DLL", "src\winconpty\dll\winconptydll.vcxproj", "{A22EC5F6-7851-4B88-AC52-47249D437A52}"
@@ -2112,6 +2110,7 @@ Global
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|Any CPU.ActiveCfg = Debug|Win32
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|ARM.ActiveCfg = Debug|Win32
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|ARM64.ActiveCfg = Debug|ARM64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|ARM64.Build.0 = Debug|ARM64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|DotNet_x64Test.Build.0 = Debug|x64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
@@ -2130,6 +2129,7 @@ Global
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|Any CPU.ActiveCfg = Release|Win32
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|ARM.ActiveCfg = Release|Win32
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|ARM64.ActiveCfg = Release|ARM64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|ARM64.Build.0 = Release|ARM64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|DotNet_x64Test.ActiveCfg = Release|x64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|DotNet_x64Test.Build.0 = Release|x64
{84848BFA-931D-42CE-9ADF-01EE54DE7890}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
@@ -2352,50 +2352,6 @@ Global
{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}.Release|x64.Build.0 = Release|x64
{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}.Release|x86.ActiveCfg = Release|Win32
{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}.Release|x86.Build.0 = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|Any CPU.ActiveCfg = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|Any CPU.Build.0 = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|Any CPU.Deploy.0 = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|ARM64.ActiveCfg = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|ARM64.Build.0 = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|ARM64.Deploy.0 = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|DotNet_x64Test.ActiveCfg = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|DotNet_x86Test.ActiveCfg = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|x64.ActiveCfg = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|x86.ActiveCfg = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|x86.Build.0 = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.AuditMode|x86.Deploy.0 = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|Any CPU.ActiveCfg = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|ARM.ActiveCfg = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|ARM64.ActiveCfg = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|x64.ActiveCfg = Debug|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|x64.Build.0 = Debug|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|x64.Deploy.0 = Debug|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|x86.ActiveCfg = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|x86.Build.0 = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Debug|x86.Deploy.0 = Debug|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|Any CPU.ActiveCfg = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|ARM.ActiveCfg = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|ARM64.ActiveCfg = Release|ARM64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|ARM64.Build.0 = Release|ARM64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|ARM64.Deploy.0 = Release|ARM64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|x64.ActiveCfg = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|x64.Build.0 = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|x64.Deploy.0 = Release|x64
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|x86.ActiveCfg = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|x86.Build.0 = Release|Win32
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1}.Release|x86.Deploy.0 = Release|Win32
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
@@ -3404,7 +3360,6 @@ Global
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{48D21369-3D7B-4431-9967-24E81292CF63} = {05500DEF-2294-41E3-AF9A-24E580B82836}
{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} = {59840756-302F-44DF-AA47-441A9D673202}
{B0AC39D6-7B40-49A9-8202-58549BAE1FB1} = {59840756-302F-44DF-AA47-441A9D673202}
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
{A22EC5F6-7851-4B88-AC52-47249D437A52} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
{A021EDFF-45C8-4DC2-BEF7-36E1B3B8CFE8} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}

View File

@@ -289,6 +289,7 @@ If you would like to ask a question that you feel doesn't warrant an issue
* You must [enable Developer Mode in the Windows Settings
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
to locally install and run Windows Terminal
* You must have [PowerShell 7 or later](https://github.com/PowerShell/PowerShell/releases/latest) installed
* You must have the [Windows 10 1903
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
installed

View File

@@ -31,7 +31,7 @@ $totalTestsExecutedCount = 0
# We assume that we only have one testRun with a given name that we care about
# We only process the last testRun with a given name (based on completedDate)
# The name of a testRun is set to the Helix queue that it was run on (e.g. windows.10.amd64.client19h1.xaml)
# The name of a testRun is set to the Helix queue that it was run on (e.g. windows.10.amd64.client21h1.xaml)
# If we have multiple test runs on the same queue that we care about, we will need to re-visit this logic
foreach ($testRun in ($testRuns.value | Sort-Object -Property "completedDate" -Descending))
{

View File

@@ -0,0 +1,24 @@
{
"Branch": [
{
"collection": "microsoft",
"project": "OS",
"repo": "os.2020",
"name": "official/rs_wdx_dxp_windev",
"workitem": "38106206",
"CheckinFiles": [
{
"source": "WindowsTerminal.app.man",
"path": "/redist/mspartners/ipa/WindowsTerminal",
"type": "File"
}
]
}
],
"Email": [
{
"sendTo": "condev",
"sendOnErrorOnly": "False"
}
]
}

View File

@@ -0,0 +1,11 @@
<PoliCheckExclusions>
<!-- All strings must be UPPER CASE -->
<!--Each of these exclusions is a folder name -if \[name]\exists in the file path, it will be skipped -->
<Exclusion Type="FolderPathFull">winrt|.git|oss|packages</Exclusion>
<!--Each of these exclusions is a folder name -if any folder or file starts with "\[name]", it will be skipped -->
<!--<Exclusion Type="FolderPathStart">ABC|XYZ</Exclusion>-->
<!--Each of these file types will be completely skipped for the entire scan -->
<Exclusion Type="FileType">.PNG|.SVG|.BMP|.ICO</Exclusion>
<!--The specified file names will be skipped during the scan regardless which folder they are in -->
<!--<Exclusion Type="FileName">ABC.TXT|XYZ.CS</Exclusion>-->
</PoliCheckExclusions>

View File

@@ -2,4 +2,5 @@
<packages>
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
</packages>

4
build/pgo/PGO.DB.proj Normal file
View File

@@ -0,0 +1,4 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Terminal.PGO.props" />
<Import Project="$(PkgMicrosoft_PGO_Helpers_Cpp)\build\Microsoft.PGO-Helpers.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Microsoft.Internal.Windows.Terminal.PGODatabase</id>
<version>0</version>
<title>Windows Terminal PGO Database</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Windows Terminal PGO Database</description>
</metadata>
<files>
<!-- The target directories for pgd files need to remain as is. PGO optimization pass will rely on this exact directory layout. -->
<file src="x64\*.pgd" target="tools\x64"/>
</files>
</package>

View File

@@ -0,0 +1,51 @@
<Project>
<PropertyGroup>
<NuGetPackageDirectory>$(MSBuildThisFileDirectory)..\..\packages</NuGetPackageDirectory>
<PkgMicrosoft_PGO_Helpers_Cpp>$(NuGetPackageDirectory)\Microsoft.Internal.PGO-Helpers.Cpp.0.2.34</PkgMicrosoft_PGO_Helpers_Cpp>
</PropertyGroup>
<!-- Get version information -->
<Import Project="$(MSBuildThisFileDirectory)..\..\custom.props" />
<PropertyGroup>
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
<PGOBranch>release-1.12</PGOBranch>
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>
<!-- Mandatory. Major version number of the PGO database which should match the version of the product. This can be hardcoded or obtained from other sources in build system. -->
<PGOPackageVersionMajor>$(VersionMajor)</PGOPackageVersionMajor>
<!-- Mandatory. Minor version number of the PGO database which should match the version of the product. This can be hardcoded or obtained from other sources in build system. -->
<PGOPackageVersionMinor>$(VersionMinor)</PGOPackageVersionMinor>
<!-- Mandatory, defaults to 0. Patch version number of the PGO database which should match the version of the product. This can be hardcoded or obtained from other sources in build system. -->
<PGOPackageVersionPatch>0</PGOPackageVersionPatch>
<!-- Optional, defaults to empty. Prerelease version number of the PGO database which should match the version of the product. This can be hardcoded or obtained from other sources in build system. -->
<PGOPackageVersionPrerelease></PGOPackageVersionPrerelease>
<!-- Mandatory. Path to nuget.config file for the project. Path is relative to where the props file will be. -->
<PGONuGetConfigPath>$(MSBuildThisFileDirectory)..\..\nuget.config</PGONuGetConfigPath>
<!-- Mandatory. Path to PGO database NuSpec, see section below. -->
<PGONuspecPath>$(MSBuildThisFileDirectory)Terminal.PGO.DB.nuspec</PGONuspecPath>
<!-- Optional, defaults to true. Should verification result in build failure or error? -->
<PGOVerifyFailureTreatedAsError>true</PGOVerifyFailureTreatedAsError>
<!-- Optional, defaults to $(IntDir)\Nuspec. Temporary path where PGD files are copied to. -->
<PGONuspecBasePath>$(PGDPathForAllArch)</PGONuspecBasePath>
<!-- Optional, defaults to true. Specifies whether to use default information for PGD files. -->
<PGOUseDefaultPGDFileInfo>true</PGOUseDefaultPGDFileInfo>
<!-- Copying the PGO runtime brings along a CRT. If we do that under normal circumstances, WAPPROJ will get its grubby hands on it and mess up all the CRT shenanigans we have to pull to make MSIX packages happy. So only pull it in for Instrument builds.-->
<PGOCopyRuntime>false</PGOCopyRuntime>
<PGOCopyRuntime Condition="'$(PGOBuildMode)' == 'Instrument'">true</PGOCopyRuntime>
</PropertyGroup>
<!-- Import PGO-Helpers -->
<Import Project="$(PkgMicrosoft_PGO_Helpers_Cpp)\build\Microsoft.PGO-Helpers.Cpp.props" />
</Project>

View File

@@ -18,6 +18,14 @@ parameters:
displayName: "Build Windows Terminal MSIX"
type: boolean
default: true
- name: runCompliance
displayName: "Run Compliance and Security Build"
type: boolean
default: true
- name: publishSymbolsToPublic
displayName: "Publish Symbols to MSDL"
type: boolean
default: true
- name: buildTerminalVPack
displayName: "Build Windows Terminal VPack"
type: boolean
@@ -34,7 +42,6 @@ parameters:
- Optimize
- Instrument
- None
- name: buildConfigurations
type: object
default:
@@ -45,6 +52,11 @@ parameters:
- x64
- x86
- arm64
- name: buildWindowsVersions
type: object
default:
- Win10
- Win11
variables:
TerminalInternalPackageVersion: "0.0.7"
@@ -61,10 +73,13 @@ jobs:
matrix:
${{ each config in parameters.buildConfigurations }}:
${{ each platform in parameters.buildPlatforms }}:
${{ config }}_${{ platform }}:
BuildConfiguration: ${{ config }}
BuildPlatform: ${{ platform }}
${{ each windowsVersion in parameters.buildWindowsVersions }}:
${{ config }}_${{ platform }}_${{ windowsVersion }}:
BuildConfiguration: ${{ config }}
BuildPlatform: ${{ platform }}
TerminalTargetWindowsVersion: ${{ windowsVersion }}
displayName: Build
timeoutInMinutes: 240
cancelTimeoutInMinutes: 1
steps:
- checkout: self
@@ -89,6 +104,17 @@ jobs:
displayName: Use NuGet 5.10
inputs:
versionSpec: 5.10
- task: NuGetAuthenticate@0
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for extraneous build actions
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: build/packages.config
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: NuGetCommand@2
displayName: NuGet custom
inputs:
@@ -96,6 +122,8 @@ jobs:
selectOrConfig: config
nugetConfigPath: NuGet.Config
arguments: restore OpenConsole.sln -SolutionDirectory $(Build.SourcesDirectory)
# Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
- template: .\templates\install-winsdk-steps.yml
- task: UniversalPackages@0
displayName: Download terminal-internal Universal Package
inputs:
@@ -111,6 +139,8 @@ jobs:
resourceFilePath: >-
src\cascadia\TerminalApp\Resources\en-US\Resources.resw
src\cascadia\TerminalApp\Resources\en-US\ContextMenu.resw
src\cascadia\TerminalControl\Resources\en-US\Resources.resw
src\cascadia\TerminalConnection\Resources\en-US\Resources.resw
@@ -119,8 +149,6 @@ jobs:
src\cascadia\TerminalSettingsEditor\Resources\en-US\Resources.resw
src\cascadia\WindowsTerminalUniversal\Resources\en-US\Resources.resw
src\cascadia\CascadiaPackage\Resources\en-US\Resources.resw
appendRelativeDir: true
localizationTarget: false
@@ -134,25 +162,29 @@ jobs:
$Files | % { Move-Item -Verbose $_.Directory $_.Directory.Parent.Parent -EA:Ignore }
pwsh: true
- task: PowerShell@2
displayName: Copy the Context Menu Loc Resources to CascadiaPackage
inputs:
filePath: ./build/scripts/Copy-ContextMenuResourcesToCascadiaPackage.ps1
pwsh: true
- task: PowerShell@2
displayName: Generate NOTICE.html from NOTICE.md
inputs:
filePath: .\build\scripts\Generate-ThirdPartyNotices.ps1
arguments: -MarkdownNoticePath .\NOTICE.md -OutputPath .\src\cascadia\CascadiaPackage\NOTICE.html
pwsh: true
- ${{ if eq(parameters.pgoBuildMode, 'Optimize') }}:
- task: PowerShell@2
displayName: Restore PGO Database
inputs:
filePath: tools/PGODatabase/restore-pgodb.ps1
workingDirectory: $(Build.SourcesDirectory)\tools\PGODatabase
- ${{ if eq(parameters.buildTerminal, true) }}:
- pwsh: |-
./build/scripts/Patch-ManifestsToWindowsVersion.ps1 -NewWindowsVersion "10.0.22000.0"
displayName: Update manifest target version to Win11 (if necessary)
condition: and(succeeded(), eq(variables['TerminalTargetWindowsVersion'], 'Win11'))
- task: VSBuild@1
displayName: Build solution **\OpenConsole.sln
condition: true
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage;Terminal\WindowsTerminalUniversal /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: true
@@ -163,21 +195,7 @@ jobs:
continueOnError: True
inputs:
PathtoPublish: $(Build.SourcesDirectory)\msbuild.binlog
ArtifactName: binlog-$(BuildPlatform)
- ${{ if eq(parameters.pgoBuildMode, 'Optimize') }}:
- task: PowerShell@2
displayName: Validate binaries are optimized
condition: and(succeeded(), eq(variables['BuildPlatform'], 'x64'))
inputs:
targetType: inline
script: >-
$Binaries = 'OpenConsole.exe', 'WindowsTerminal.exe', 'TerminalApp.dll', 'TerminalConnection.dll', 'Microsoft.Terminal.Control.dll', 'Microsoft.Terminal.Remoting.dll', 'Microsoft.Terminal.Settings.Editor.dll', 'Microsoft.Terminal.Settings.Model.dll'
foreach ($BinFile in $Binaries) {
& "$(Build.SourcesDirectory)\tools\PGODatabase\verify-pgo.ps1" "$(Build.SourcesDirectory)/src/cascadia/CascadiaPackage/bin/$(BuildPlatform)/$(BuildConfiguration)/$BinFile"
}
ArtifactName: binlog-$(BuildPlatform)-$(TerminalTargetWindowsVersion)
- task: PowerShell@2
displayName: Check MSIX for common regressions
inputs:
@@ -190,7 +208,6 @@ jobs:
- ${{ if eq(parameters.buildWPF, true) }}:
- task: VSBuild@1
displayName: Build solution **\OpenConsole.sln for PublicTerminalCore
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
@@ -203,8 +220,6 @@ jobs:
filePath: build\scripts\Index-Pdbs.ps1
arguments: -SearchDir '$(Build.SourcesDirectory)' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
errorActionPreference: silentlyContinue
- task: ComponentGovernanceComponentDetection@0
displayName: Component Detection
- task: PowerShell@2
displayName: Run Unit Tests
condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'x86')))
@@ -234,15 +249,18 @@ jobs:
TargetFolder: $(Build.ArtifactStagingDirectory)/appx
OverWrite: true
flattenFolders: true
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
displayName: 'Generate SBOM manifest'
inputs:
BuildDropPath: '$(System.ArtifactsDirectory)/appx'
- task: PublishBuildArtifacts@1
displayName: Publish Artifact (appx)
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)
ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
- ${{ if eq(parameters.buildWPF, true) }}:
- task: CopyFiles@2
displayName: Copy PublicTerminalCore.dll to Artifacts
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
inputs:
Contents: >-
**/PublicTerminalCore.dll
@@ -253,20 +271,31 @@ jobs:
flattenFolders: true
- task: PublishBuildArtifacts@1
displayName: Publish Artifact (PublicTerminalCore)
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/wpf
ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)
ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
- task: PublishSymbols@2
displayName: Publish symbols path
continueOnError: True
inputs:
SearchPattern: '**/*.pdb'
SearchPattern: |
$(Build.SourcesDirectory)/bin/**/*.pdb
$(Build.SourcesDirectory)/bin/**/*.exe
$(Build.SourcesDirectory)/bin/**/*.dll
IndexSources: false
SymbolServerType: TeamServices
- ${{ if eq(parameters.runCompliance, true) }}:
- template: ./templates/build-console-compliance-job.yml
- ${{ if eq(parameters.buildTerminal, true) }}:
- job: BundleAndSign
strategy:
matrix:
${{ each windowsVersion in parameters.buildWindowsVersions }}:
${{ windowsVersion }}:
TerminalTargetWindowsVersion: ${{ windowsVersion }}
displayName: Create and sign AppX/MSIX bundles
dependsOn: Build
steps:
@@ -278,25 +307,21 @@ jobs:
displayName: Package ES - Setup Build
inputs:
disableOutputRedirect: true
- task: DownloadBuildArtifacts@0
displayName: Download Artifacts (*.appx, *.msix)
inputs:
downloadType: specific
itemPattern: >-
**/*.msix
**/*.appx
extractTars: false
- task: PowerShell@2
- ${{ each platform in parameters.buildPlatforms }}:
- task: DownloadBuildArtifacts@0
displayName: Download Artifacts ${{ platform }} $(TerminalTargetWindowsVersion)
inputs:
artifactName: appx-${{ platform }}-Release-$(TerminalTargetWindowsVersion)
# Add 3000 to the major version component, but only for the bundle.
# This is to ensure that it is newer than "2022.xx.yy.zz" or whatever the original bundle versions were before
# we switched to uniform naming.
- pwsh: |-
$VersionEpoch = 3000
$Components = "$(XES_APPXMANIFESTVERSION)" -Split "\."
$Components[0] = ([int]$Components[0] + $VersionEpoch)
$BundleVersion = $Components -Join "."
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
displayName: Create WindowsTerminal*.msixbundle
inputs:
filePath: build\scripts\Create-AppxBundle.ps1
arguments: -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion 0.0.0.0 -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
- task: PowerShell@2
displayName: Create WindowsTerminalUniversal*.msixbundle
inputs:
filePath: build\scripts\Create-AppxBundle.ps1
arguments: -InputPath "$(System.ArtifactsDirectory)" -ProjectName WindowsTerminalUniversal -BundleVersion $(XES_APPXMANIFESTVERSION) -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminalUniversal_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
- task: EsrpCodeSigning@1
displayName: Submit *.msixbundle to ESRP for code signing
inputs:
@@ -331,11 +356,12 @@ jobs:
"ToolVersion": "1.0"
}
]
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: appxbundle-signed'
inputs:
PathtoPublish: $(System.ArtifactsDirectory)
ArtifactName: appxbundle-signed
ArtifactName: appxbundle-signed-$(TerminalTargetWindowsVersion)
- ${{ if eq(parameters.buildWPF, true) }}:
- job: PackageAndSignWPF
@@ -355,31 +381,26 @@ jobs:
displayName: Package ES - Setup Build
inputs:
disableOutputRedirect: true
- task: DownloadBuildArtifacts@0
displayName: Download x86 PublicTerminalCore
inputs:
artifactName: wpf-dll-x86-$(BuildConfiguration)
itemPattern: '**/*.dll'
downloadPath: bin\Win32\$(BuildConfiguration)\
extractTars: false
- task: DownloadBuildArtifacts@0
displayName: Download x64 PublicTerminalCore
inputs:
artifactName: wpf-dll-x64-$(BuildConfiguration)
itemPattern: '**/*.dll'
downloadPath: bin\x64\$(BuildConfiguration)\
extractTars: false
- ${{ each platform in parameters.buildPlatforms }}:
- task: DownloadBuildArtifacts@0
displayName: Download ${{ platform }} PublicTerminalCore
inputs:
artifactName: wpf-dll-${{ platform }}-$(BuildConfiguration)-Win10
itemPattern: '**/*.dll'
downloadPath: bin\${{ platform }}\$(BuildConfiguration)\
extractTars: false
- task: PowerShell@2
displayName: Move downloaded artifacts up a level
displayName: Move downloaded artifacts around
inputs:
targetType: inline
# Find all artifact files and move them up a directory. Ugh.
script: >-
script: |-
Get-ChildItem bin -Recurse -Directory -Filter wpf-dll-* | % {
$_ | Get-ChildItem -Recurse -File | % {
Move-Item -Verbose $_.FullName $_.Directory.Parent.FullName
}
}
Move-Item bin\x86 bin\Win32
- task: NuGetToolInstaller@1
displayName: Use NuGet 5.10.0
inputs:
@@ -402,7 +423,10 @@ jobs:
displayName: Publish symbols path
continueOnError: True
inputs:
SearchPattern: '**/*.pdb'
SearchPattern: |
$(Build.SourcesDirectory)/bin/**/*.pdb
$(Build.SourcesDirectory)/bin/**/*.exe
$(Build.SourcesDirectory)/bin/**/*.dll
IndexSources: false
SymbolServerType: TeamServices
SymbolsArtifactName: Symbols_WPF_$(BuildConfiguration)
@@ -444,6 +468,71 @@ jobs:
PathtoPublish: $(Build.ArtifactStagingDirectory)\nupkg
ArtifactName: wpf-nupkg-$(BuildConfiguration)
- ${{ if eq(parameters.publishSymbolsToPublic, true) }}:
- job: PublishSymbols
displayName: Publish Symbols
dependsOn: BundleAndSign
steps:
- checkout: self
clean: true
fetchDepth: 1
submodules: true
- task: PkgESSetupBuild@12
displayName: Package ES - Setup Build
# Download the appx-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
- ${{ each platform in parameters.buildPlatforms }}:
- ${{ each windowsVersion in parameters.buildWindowsVersions }}:
- task: DownloadBuildArtifacts@0
displayName: Download Symbols ${{ platform }} ${{ windowsVersion }}
inputs:
artifactName: appx-${{ platform }}-Release-${{ windowsVersion }}
# It seems easier to do this -- download every appxsym -- then enumerate all the PDBs in the build directory for the
# public symbol push. Otherwise, we would have to list all of the PDB files one by one.
- pwsh: |-
mkdir $(Build.SourcesDirectory)/appxsym-temp
Get-ChildItem "$(System.ArtifactsDirectory)" -Filter *.appxsym -Recurse | % {
$src = $_.FullName
$dest = Join-Path "$(Build.SourcesDirectory)/appxsym-temp/" $_.Name
mkdir $dest
Write-Host "Extracting $src to $dest..."
tar -x -v -f $src -C $dest
}
displayName: Extract symbols for public consumption
# Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
- template: .\templates\install-winsdk-steps.yml
- task: PowerShell@2
displayName: Source Index PDBs (the public ones)
inputs:
filePath: build\scripts\Index-Pdbs.ps1
arguments: -SearchDir '$(Build.SourcesDirectory)/appxsym-temp' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
# Publish the app symbols to the public MSDL symbol server
# accessible via https://msdl.microsoft.com/download/symbols
- task: PublishSymbols@2
displayName: 'Publish app symbols to MSDL'
inputs:
symbolsFolder: '$(Build.SourcesDirectory)/appxsym-temp'
searchPattern: '**/*.pdb'
SymbolsMaximumWaitTime: 30
SymbolServerType: 'TeamServices'
SymbolsProduct: 'Windows Terminal Application Binaries'
SymbolsVersion: '$(XES_APPXMANIFESTVERSION)'
# The ADO task does not support indexing of GitHub sources.
indexSources: false
detailedLog: true
# There is a bug which causes this task to fail if LIB includes an inaccessible path (even though it does not depend on it).
# To work around this issue, we just force LIB to be any dir that we know exists.
# Copied from https://github.com/microsoft/icu/blob/f869c214adc87415dfe751d81f42f1bca55dcf5f/build/azure-nuget.yml#L564-L583
env:
LIB: $(Build.SourcesDirectory)
ArtifactServices_Symbol_AccountName: microsoftpublicsymbols
ArtifactServices_Symbol_PAT: $(ADO_microsoftpublicsymbols_PAT)
- ${{ if eq(parameters.buildTerminalVPack, true) }}:
- job: VPack
displayName: Create Windows vPack
@@ -457,7 +546,7 @@ jobs:
- task: DownloadBuildArtifacts@0
displayName: Download Build Artifacts
inputs:
artifactName: appxbundle-signed
artifactName: appxbundle-signed-Win11
extractTars: false
- task: PowerShell@2
displayName: Rename and stage packages for vpack
@@ -466,7 +555,7 @@ jobs:
script: >-
# Rename to known/fixed name for Windows build system
Get-ChildItem Microsoft.WindowsTerminal_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
Get-ChildItem Microsoft.WindowsTerminal_Win11_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
# Create vpack directory and place item inside
@@ -474,14 +563,25 @@ jobs:
mkdir WindowsTerminal.app
mv Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle .\WindowsTerminal.app\
workingDirectory: $(System.ArtifactsDirectory)\appxbundle-signed
workingDirectory: $(System.ArtifactsDirectory)\appxbundle-signed-Win11
- task: PkgESVPack@12
displayName: 'Package ES - VPack'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
sourceDirectory: $(System.ArtifactsDirectory)\appxbundle-signed\WindowsTerminal.app
description: Windows Terminal pre-install application
sourceDirectory: $(System.ArtifactsDirectory)\appxbundle-signed-Win11\WindowsTerminal.app
description: VPack for the Windows Terminal Application
pushPkgName: WindowsTerminal.app
owner: condev
owner: conhost
- task: PublishPipelineArtifact@1
displayName: 'Copy VPack Manifest to Drop'
inputs:
targetPath: $(XES_VPACKMANIFESTDIRECTORY)
artifactName: VPackManifest
- task: PkgESFCIBGit@12
displayName: 'Submit VPack Manifest to Windows'
inputs:
configPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
artifactsDirectory: $(XES_VPACKMANIFESTDIRECTORY)
prTimeOut: 5
...

View File

@@ -25,6 +25,17 @@ jobs:
inputs:
versionSpec: 4.8.1
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for extraneous build actions
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: build/packages.config
restoreDirectory: '$(Build.SourcesDirectory)\packages'
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2

View File

@@ -0,0 +1,222 @@
jobs:
- job: Compliance
# We don't *need* a matrix but there's no other way to set parameters on a "job"
# in the AzDO YAML syntax. It would have to be a "stage" or a "template".
# Doesn't matter. We're going to do compliance on Release x64 because
# that's the one all the tooling works against for sure.
strategy:
matrix:
Release_x64:
BuildConfiguration: Release
BuildPlatform: x64
displayName: Validate Security and Compliance
timeoutInMinutes: 240
steps:
- checkout: self
clean: true
submodules: true
persistCredentials: True
- task: PkgESSetupBuild@12
displayName: Package ES - Setup Build
inputs:
disableOutputRedirect: true
- task: PowerShell@2
displayName: Rationalize Build Platform
inputs:
targetType: inline
script: >-
$Arch = "$(BuildPlatform)"
If ($Arch -Eq "x86") { $Arch = "Win32" }
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
- task: NuGetToolInstaller@1
displayName: Use NuGet 5.10
inputs:
versionSpec: 5.10
- task: NuGetAuthenticate@0
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for extraneous build actions
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: build/packages.config
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: NuGetCommand@2
displayName: NuGet custom
inputs:
command: custom
selectOrConfig: config
nugetConfigPath: NuGet.Config
arguments: restore OpenConsole.sln -SolutionDirectory $(Build.SourcesDirectory)
- task: UniversalPackages@0
displayName: Download terminal-internal Universal Package
inputs:
feedListDownload: 2b3f8893-a6e8-411f-b197-a9e05576da48
packageListDownload: e82d490c-af86-4733-9dc4-07b772033204
versionListDownload: $(TerminalInternalPackageVersion)
- task: TouchdownBuildTask@1
displayName: Download Localization Files
inputs:
teamId: 7105
authId: $(TouchdownAppId)
authKey: $(TouchdownAppKey)
resourceFilePath: >-
src\cascadia\TerminalApp\Resources\en-US\Resources.resw
src\cascadia\TerminalControl\Resources\en-US\Resources.resw
src\cascadia\TerminalConnection\Resources\en-US\Resources.resw
src\cascadia\TerminalSettingsModel\Resources\en-US\Resources.resw
src\cascadia\TerminalSettingsEditor\Resources\en-US\Resources.resw
src\cascadia\CascadiaPackage\Resources\en-US\Resources.resw
appendRelativeDir: true
localizationTarget: false
pseudoSetting: Included
- task: PowerShell@2
displayName: Move Loc files one level up
inputs:
targetType: inline
script: >-
$Files = Get-ChildItem . -R -Filter 'Resources.resw' | ? FullName -Like '*en-US\*\Resources.resw'
$Files | % { Move-Item -Verbose $_.Directory $_.Directory.Parent.Parent -EA:Ignore }
pwsh: true
# 1ES Component Governance onboarding (Detects open source components). See https://docs.opensource.microsoft.com/tools/cg.html
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: Component Detection
# # PREfast and PoliCheck need Node. Install that first.
- task: NodeTool@0
# !!! NOTE !!! Run PREfast first. Some of the other tasks are going to run on a completed build.
# PREfast is going to build the code as a part of its analysis and the generated sources
# and output binaries will be sufficient for the rest of the analysis.
# If you disable this, the other tasks won't likely work. You would have to add a build
# step instead that builds the code normally before calling them.
# Also... PREfast will rebuild anyway so that's why we're not running a normal build first.
# Waste of time to build twice.
# PREfast. See https://www.1eswiki.com/wiki/SDL_Native_Rules_Build_Task
# The following 1ES tasks all operate completely differently and have a different syntax for usage.
# Most notable is every one of them has a different way of excluding things.
# Go see their 1eswiki.com pages to figure out how to exclude things.
# When writing exclusions, try to make them narrow so when new projects/binaries are added, they
# cause an error here and have to be explicitly pulled out. Don't write an exclusion so broad
# that it will catch other new stuff.
# https://www.1eswiki.com/wiki/PREfast_Build_Task
# Builds the project with C/C++ static analysis tools to find coding flaws and vulnerabilities
# !!! WARNING !!! It doesn't work with WAPPROJ packaging projects. Build the sub-projects instead.
- task: securedevelopmentteam.vss-secure-development-tools.build-task-prefast.SDLNativeRules@3
displayName: 'Run the PREfast SDL Native Rules for MSBuild'
condition: succeededOrFailed()
inputs:
msBuildCommandline: msbuild.exe /nologo /m /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }} /p:WindowsTerminalReleaseBuild=true /p:platform=$(BuildPlatform) /p:configuration=$(BuildConfiguration) /t:Terminal\Window\WindowsTerminal /p:VisualStudioVersion=16.0 $(Build.SourcesDirectory)\OpenConsole.sln
# Copies output from PREfast SDL Native Rules task to expected location for consumption by PkgESSecComp
- task: CopyFiles@1
displayName: 'Copy PREfast xml files to SDLNativeRulesDir'
inputs:
SourceFolder: '$(Agent.BuildDirectory)'
Contents: |
**\*.nativecodeanalysis.xml
TargetFolder: '$(Agent.BuildDirectory)\_sdt\logs\SDLNativeRules'
# https://www.1eswiki.com/index.php?title=PoliCheck_Build_Task
# Scans the text of source code, comments, and content for terminology that could be sensitive for legal, cultural, or geopolitical reasons.
# (Also finds vulgarities... takes all the fun out of everything.)
- task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@2
displayName: 'Run PoliCheck'
inputs:
targetType: F
targetArgument: $(Build.SourcesDirectory)
result: PoliCheck.xml
optionsFC: 1
optionsXS: 1
optionsUEPath: $(Build.SourcesDirectory)\build\config\PolicheckExclusions.xml
optionsHMENABLE: 0
continueOnError: true
# https://www.1eswiki.com/wiki/CredScan_Azure_DevOps_Build_Task
# Searches through source code and build outputs for a credential left behind in the open
- task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3
displayName: 'Run CredScan'
inputs:
outputFormat: pre
# suppressionsFile: LocalSuppressions.json
batchSize: 20
debugMode: false
continueOnError: true
# https://www.1eswiki.com/wiki/BinSkim_Build_Task
# Searches managed and unmanaged binaries for known security vulnerabilities.
- task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@4
displayName: 'Run BinSkim'
inputs:
TargetPattern: guardianGlob
# See https://aka.ms/gdn-globs for how to do match patterns
AnalyzeTargetGlob: $(Build.SourcesDirectory)\bin\**\*.dll;$(Build.SourcesDirectory)\bin\**\*.exe;-:file|**\Microsoft.UI.Xaml.dll;-:file|**\Microsoft.Toolkit.Win32.UI.XamlHost.dll;-:file|**\vcruntime*.dll;-:file|**\vcomp*.dll;-:file|**\vccorlib*.dll;-:file|**\vcamp*.dll;-:file|**\msvcp*.dll;-:file|**\concrt*.dll;-:file|**\TerminalThemeHelpers*.dll;-:file|**\cpprest*.dll
continueOnError: true
# Set XES_SERIALPOSTBUILDREADY to run Security and Compliance task once per build
- powershell: Write-Host “##vso[task.setvariable variable=XES_SERIALPOSTBUILDREADY;]true”
displayName: 'Set XES_SERIALPOSTBUILDREADY Vars'
# https://www.osgwiki.com/wiki/Package_ES_Security_and_Compliance
# Does a few things:
# - Ensures that Windows-required compliance tasks are run either inside this task
# or were run as a previous step prior to this one
# (PREfast, PoliCheck, Credscan)
# - Runs Windows-specific compliance tasks inside the task
# + CheckCFlags - ensures that compiler and linker flags meet Windows standards
# + CFGCheck/XFGCheck - ensures that Control Flow Guard (CFG) or
# eXtended Flow Guard (XFG) are enabled on binaries
# NOTE: CFG is deprecated and XFG isn't fully ready yet.
# NOTE2: CFG fails on an XFG'd binary
# - Brokers all security/compliance task logs to "Trust Services Automation (TSA)" (https://aka.ms/tsa)
# which is a system that maps all errors into the appropriate bug database
# template for each organization since they all vary. It should also suppress
# new bugs when one already exists for the product.
# This one is set up to go to the OS repository and use the given parameters
# to file bugs to our AzDO product path.
# If we don't use PkgESSecComp to do this for us, we need to install the TSA task
# ourselves in this pipeline to finalize data upload and bug creation.
# !!! NOTE !!! This task goes *LAST* after any other compliance tasks so it catches their logs
- task: PkgESSecComp@10
displayName: 'Security and Compliance tasks'
inputs:
fileNewBugs: false
areaPath: 'OS\WDX\DXP\WinDev\Terminal'
teamProject: 'OS'
iterationPath: 'OS\Future'
bugTags: 'TerminalReleaseCompliance'
scanAll: true
errOnBugs: false
failOnStdErr: true
taskLogVerbosity: Diagnostic
secCompConfigFromTask: |
# Overrides default build sources directory
sourceTargetOverrideAll: $(Build.SourcesDirectory)
# Overrides default build binaries directory when "Scan all" option is specified
binariesTargetOverrideAll: $(Build.SourcesDirectory)\bin
# Set the tools to false if they should not run in the build
tools:
- toolName: CheckCFlags
enable: true
- toolName: CFGCheck
enable: true
- toolName: Policheck
enable: false
- toolName: CredScan
enable: false
- toolName: XFGCheck
enable: false

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- template: build-console-steps.yml
parameters:
additionalBuildArguments: ${{ parameters.additionalBuildArguments }}
additionalBuildArguments: '${{ parameters.additionalBuildArguments }}'
- template: helix-runtests-job.yml
parameters:
@@ -52,3 +52,4 @@ jobs:
- ProcessTestResults
pgoArtifact: 'PGO'
platform: ${{ parameters.platform }}
configuration: ${{ parameters.configuration }}

View File

@@ -12,17 +12,10 @@ steps:
inputs:
versionSpec: 5.2.0
- task: NuGetAuthenticate@0
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for solution
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: OpenConsole.sln
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for extraneous build actions
inputs:
@@ -32,6 +25,15 @@ steps:
restoreSolution: build/packages.config
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for solution
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: OpenConsole.sln
restoreDirectory: '$(Build.SourcesDirectory)\packages'
# The environment variable VCToolsInstallDir isn't defined on lab machines, so we need to retrieve it ourselves.
- script: |
"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -Latest -requires Microsoft.Component.MSBuild -property InstallationPath > %TEMP%\vsinstalldir.txt
@@ -47,14 +49,6 @@ steps:
inputs:
filename: 'set'
- task: powershell@2
displayName: 'Restore PGO database'
condition: eq(variables['PGOBuildMode'], 'Optimize')
inputs:
targetType: filePath
workingDirectory: $(Build.SourcesDirectory)\tools\PGODatabase
filePath: $(Build.SourcesDirectory)\tools\PGODatabase\restore-pgodb.ps1
- task: VSBuild@1
displayName: 'Build solution **\OpenConsole.sln'
inputs:
@@ -62,7 +56,7 @@ steps:
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: "${{ parameters.additionalBuildArguments }}"
msbuildArgs: "${{ parameters.additionalBuildArguments }} /p:PGOBuildMode=$(PGOBuildMode) /bl:$(Build.SourcesDirectory)\\msbuild.binlog"
clean: true
maximumCpuCount: true
@@ -95,18 +89,6 @@ steps:
If ($Arch -Eq "x86") { $Arch = "Win32" }
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
- task: PowerShell@2
displayName: 'Validate binaries are optimized'
condition: eq(variables['pgoBuildMode'], 'Optimize')
inputs:
targetType: inline
script: |
$Binaries = 'OpenConsole.exe', 'WindowsTerminal.exe', 'TerminalApp.dll', 'TerminalConnection.dll', 'Microsoft.Terminal.Control.dll', 'Microsoft.Terminal.Remoting.dll', 'Microsoft.Terminal.Settings.Editor.dll', 'Microsoft.Terminal.Settings.Model.dll'
foreach ($BinFile in $Binaries)
{
& "$(Build.SourcesDirectory)\tools\PGODatabase\verify-pgo.ps1" "$(Build.SourcesDirectory)/bin/$(RationalizedBuildPlatform)/$(BuildConfiguration)/$BinFile"
}
- task: PowerShell@2
displayName: 'Run Unit Tests'
inputs:
@@ -177,6 +159,8 @@ steps:
$(Build.SourcesDirectory)/bin/$(RationalizedBuildPlatform)/$(BuildConfiguration)/*.dll
$(Build.SourcesDirectory)/bin/$(RationalizedBuildPlatform)/$(BuildConfiguration)/*.xml
**/Microsoft.VCLibs.*.appx
**/*unit.test*.dll
**/*unit.test*.manifest
**/TestHostApp/*.exe
**/TestHostApp/*.dll
**/TestHostApp/*.xml
@@ -211,3 +195,11 @@ steps:
PathtoPublish: '$(Build.ArtifactStagingDirectory)/$(BuildConfiguration)/PGO'
ArtifactName: 'PGO'
condition: and(succeeded(), eq(variables['PGOBuildMode'], 'Instrument'))
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: binlog'
condition: failed()
continueOnError: True
inputs:
PathtoPublish: $(Build.SourcesDirectory)\msbuild.binlog
ArtifactName: binlog-$(BuildPlatform)

View File

@@ -14,8 +14,8 @@ parameters:
platform: ''
# if 'useBuildOutputFromBuildId' is set, we will default to using a build from this pipeline:
useBuildOutputFromPipeline: $(System.DefinitionId)
openHelixTargetQueues: 'windows.10.amd64.client19h1.open.xaml'
closedHelixTargetQueues: 'windows.10.amd64.client19h1.xaml'
openHelixTargetQueues: 'windows.10.amd64.client21h1.open.xaml'
closedHelixTargetQueues: 'windows.10.amd64.client21h1.xaml'
jobs:
- job: ${{ parameters.name }}

View File

@@ -0,0 +1,9 @@
parameters:
sdkVersion: 18362
steps:
- task: powershell@2
inputs:
targetType: filePath
filePath: build\scripts\Install-WindowsSdkISO.ps1
arguments: ${{ parameters.sdkVersion }}
displayName: 'Install Windows SDK (${{ parameters.sdkVersion }})'

View File

@@ -11,7 +11,7 @@ jobs:
vmImage: 'windows-2019'
variables:
artifactsPath: $(Build.SourcesDirectory)\Artifacts
pgoToolsPath: $(Build.SourcesDirectory)\tools\PGODatabase
pgoToolsPath: $(Build.SourcesDirectory)\build\PGO
nuspecPath: $(pgoToolsPath)\NuSpecs
nuspecFilename: PGO.nuspec
@@ -30,28 +30,22 @@ jobs:
inputs:
versionSpec: 5.8.0
- task: CopyFiles@2
displayName: 'Copy pgd files to NuGet build directory'
inputs:
sourceFolder: $(artifactsPath)\${{ parameters.pgoArtifact }}
contents: '**\*.pgd'
targetFolder: $(nuspecPath)\tools
- task: powershell@2
displayName: 'Generate NuSpec file'
inputs:
targetType: filePath
filePath: $(pgoToolsPath)\generate-nuspec.ps1
workingDirectory: $(pgoToolsPath)
arguments: $(nuspecPath)\$(nuspecFilename).template $(nuspecPath)\$(nuspecFilename)
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: 'NuGet pack'
displayName: Restore NuGet packages for extraneous build actions
inputs:
command: pack
packagesToPack: '$(nuspecPath)\$(nuspecFilename)'
basePath: '$(nuspecPath)'
packDestination: '$(Build.ArtifactStagingDirectory)'
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: build/packages.config
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: MSBuild@1
displayName: 'Create PGO Nuget'
inputs:
solution: $(pgoToolsPath)\PGO.DB.proj
msbuildArguments: '/t:CreatePGONuGet /p:PGOBuildMode=Instrument /p:PGDPathForAllArch=$(artifactsPath)\${{ parameters.pgoArtifact }} /p:PGOOutputPath=$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
inputs:
@@ -69,4 +63,4 @@ jobs:
# This is the name of that connection
publishFeedCredentials: 'Terminal Public Artifact Feed'
feedsToUse: config
nugetConfigPath: '$(Build.SourcesDirectory)/NuGet.config'
nugetConfigPath: '$(Build.SourcesDirectory)/NuGet.config'

View File

@@ -2,6 +2,7 @@ parameters:
dependsOn: ''
pgoArtifact: PGO
platform: ''
configuration: ''
jobs:
- job: MergePGD
@@ -12,6 +13,7 @@ jobs:
artifactsPath: $(Build.SourcesDirectory)\Artifacts
pgoArtifactsPath: $(artifactsPath)\${{ parameters.pgoArtifact }}
buildPlatform: ${{ parameters.platform }}
buildConfiguration: ${{ parameters.configuration }}
steps:
# The environment variable VCToolsInstallDir isn't defined on lab machines, so we need to retrieve it ourselves.
@@ -24,58 +26,36 @@ jobs:
echo ##vso[task.setvariable variable=VCToolsInstallDir]%VCToolsInstallDir%
displayName: 'Retrieve VC tools directory'
- task: NuGetToolInstaller@0
displayName: 'Use NuGet 5.2.0'
inputs:
versionSpec: 5.2.0
- task: NuGetAuthenticate@0
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: Restore NuGet packages for extraneous build actions
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: build/packages.config
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: DownloadBuildArtifacts@0
inputs:
artifactName: ${{ parameters.pgoArtifact }}
downloadPath: $(artifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge WindowsTerminal*.pgc WindowsTerminal.pgd
displayName: 'Merge Terminal pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge OpenConsole*.pgc OpenConsole.pgd
displayName: 'Merge OpenConsole pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge Microsoft.Terminal.Control*.pgc Microsoft.Terminal.Control.pgd
displayName: 'Merge Microsoft.Terminal.Control pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge Microsoft.Terminal.Remoting*.pgc Microsoft.Terminal.Remoting.pgd
displayName: 'Merge Microsoft.Terminal.Remoting pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge Microsoft.Terminal.Settings.Editor*.pgc Microsoft.Terminal.Settings.Editor.pgd
displayName: 'Merge Microsoft.Terminal.Settings.Editor pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge Microsoft.Terminal.Settings.Model*.pgc Microsoft.Terminal.Settings.Model.pgd
displayName: 'Merge Microsoft.Terminal.Settings.Model pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge TerminalApp*.pgc TerminalApp.pgd
displayName: 'Merge TerminalApp pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- script: |
cd $(buildPlatform)
"%VCToolsInstallDir%\bin\hostx64\x64\pgomgr.exe" /merge TerminalConnection*.pgc TerminalConnection.pgd
displayName: 'Merge TerminalConnection pgc files into pgd'
workingDirectory: $(pgoArtifactsPath)
- task: MSBuild@1
displayName: Merge counts into PGD
inputs:
solution: $(Build.SourcesDirectory)\OpenConsole.sln
platform: $(buildPlatform)
configuration: $(buildConfiguration)
msbuildArguments: '/t:MergePGOCounts /p:PGOBuildMode=Instrument /p:PGDPath=$(pgoArtifactsPath)\$(buildPlatform) /p:PGCRootPath=$(pgoArtifactsPath)\$(buildPlatform)'
- task: CopyFiles@2
displayName: 'Copy merged pgd to artifact staging'
@@ -87,4 +67,4 @@ jobs:
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(Build.ArtifactStagingDirectory)
artifactName: ${{ parameters.pgoArtifact }}
artifactName: ${{ parameters.pgoArtifact }}

View File

@@ -0,0 +1,34 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
$LocalizationsFromContextMenu = Get-ChildItem ./src/cascadia/TerminalApp/Resources -Recurse -Filter ContextMenu.resw
$Languages = [System.Collections.HashTable]::New()
$LocalizationsFromContextMenu | ForEach-Object {
$Languages[$_.Directory.Name] = $_
}
ForEach ($pair in $Languages.GetEnumerator()) {
$LanguageDir = "./src/cascadia/CascadiaPackage/Resources/$($pair.Key)"
$ResPath = "$LanguageDir/Resources.resw"
$PreexistingResw = Get-Item $ResPath -EA:Ignore
If ($null -eq $PreexistingResw) {
Write-Host "Copying $($pair.Value.FullName) to $ResPath"
New-Item -type Directory $LanguageDir -EA:Ignore
Copy-Item $pair.Value.FullName $ResPath
} Else {
# Merge Them!
Write-Host "Merging $($pair.Value.FullName) into $ResPath"
$existingXml = [xml](Get-Content $PreexistingResw.FullName)
$newXml = [xml](Get-Content $pair.Value.FullName)
$newDataKeys = $newXml.root.data.name
$existingXml.root.data | % {
If ($_.name -in $newDataKeys) {
$null = $existingXml.root.RemoveChild($_)
}
}
$newXml.root.data | % {
$null = $existingXml.root.AppendChild($existingXml.ImportNode($_, $true))
}
$existingXml.Save($PreexistingResw.FullName)
}
}

View File

@@ -23,6 +23,7 @@ $mappedFiles = New-Object System.Collections.ArrayList
foreach ($file in (Get-ChildItem -r:$recursive "$SearchDir\*.pdb"))
{
$mappedFiles = New-Object System.Collections.ArrayList
Write-Verbose "Found $file"
$ErrorActionPreference = "Continue" # Azure Pipelines defaults to "Stop", continue past errors in this script.
@@ -50,7 +51,7 @@ foreach ($file in (Get-ChildItem -r:$recursive "$SearchDir\*.pdb"))
if ($relative)
{
$mapping = $allFiles[$i] + "*$relative"
$mappedFiles.Add($mapping)
$ignore = $mappedFiles.Add($mapping)
Write-Verbose "Mapped path $($i): $mapping"
}
@@ -78,7 +79,26 @@ $($mappedFiles -join "`r`n")
SRCSRV: end ------------------------------------------------
"@ | Set-Content $pdbstrFile
Write-Host
Write-Host
Write-Host (Get-Content $pdbstrFile)
Write-Host
Write-Host
Write-Host "$pdbstrExe -p:""$file"" -w -s:srcsrv -i:$pdbstrFile"
& $pdbstrExe -p:"$file" -w -s:srcsrv -i:$pdbstrFile
Write-Host
Write-Host
Write-Host "$pdbstrExe -p:""$file"" -r -s:srcsrv"
& $pdbstrExe -p:"$file" -r -s:srcsrv
Write-Host
Write-Host
Write-Host "$srctoolExe $file"
& $srctoolExe "$file"
Write-Host
Write-Host
}
# Return with exit 0 to override any weird error code from other tools

View File

@@ -0,0 +1,346 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true, Position=0)]
[string]$buildNumber)
# Ensure the error action preference is set to the default for PowerShell3, 'Stop'
$ErrorActionPreference = 'Stop'
# Constants
$WindowsSDKOptions = @("OptionId.UWPCpp", "OptionId.DesktopCPPx64", "OptionId.DesktopCPPx86", "OptionId.DesktopCPPARM64", "OptionId.DesktopCPPARM", "OptionId.WindowsDesktopDebuggers")
$WindowsSDKRegPath = "HKLM:\Software\WOW6432Node\Microsoft\Windows Kits\Installed Roots"
$WindowsSDKRegRootKey = "KitsRoot10"
$WindowsSDKVersion = "10.0.$buildNumber.0"
$WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options"
$StrongNameRegPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification"
$PublicKeyTokens = @("31bf3856ad364e35")
if ($buildNumber -notmatch "^\d{5,}$")
{
Write-Host "ERROR: '$buildNumber' doesn't look like a windows build number"
Write-Host
Exit 1
}
function Download-File
{
param ([string] $outDir,
[string] $downloadUrl,
[string] $downloadName)
$downloadPath = Join-Path $outDir "$downloadName.download"
$downloadDest = Join-Path $outDir $downloadName
$downloadDestTemp = Join-Path $outDir "$downloadName.tmp"
Write-Host -NoNewline "Downloading $downloadName..."
$retries = 10
$downloaded = $false
while (-not $downloaded)
{
try
{
$webclient = new-object System.Net.WebClient
$webclient.DownloadFile($downloadUrl, $downloadPath)
$downloaded = $true
}
catch [System.Net.WebException]
{
Write-Host
Write-Warning "Failed to fetch updated file from $downloadUrl : $($error[0])"
if (!(Test-Path $downloadDest))
{
if ($retries -gt 0)
{
Write-Host "$retries retries left, trying download again"
$retries--
start-sleep -Seconds 10
}
else
{
throw "$downloadName was not found at $downloadDest"
}
}
else
{
Write-Warning "$downloadName may be out of date"
}
}
}
Unblock-File $downloadPath
$downloadDestTemp = $downloadPath;
# Delete and rename to final dest
Write-Host "testing $downloadDest"
if (Test-Path $downloadDest)
{
Write-Host "Deleting: $downloadDest"
Remove-Item $downloadDest -Force
}
Move-Item -Force $downloadDestTemp $downloadDest
Write-Host "Done"
return $downloadDest
}
function Get-ISODriveLetter
{
param ([string] $isoPath)
$diskImage = Get-DiskImage -ImagePath $isoPath
if ($diskImage)
{
$volume = Get-Volume -DiskImage $diskImage
if ($volume)
{
$driveLetter = $volume.DriveLetter
if ($driveLetter)
{
$driveLetter += ":"
return $driveLetter
}
}
}
return $null
}
function Mount-ISO
{
param ([string] $isoPath)
# Check if image is already mounted
$isoDrive = Get-ISODriveLetter $isoPath
if (!$isoDrive)
{
Mount-DiskImage -ImagePath $isoPath -StorageType ISO | Out-Null
}
$isoDrive = Get-ISODriveLetter $isoPath
Write-Verbose "$isoPath mounted to ${isoDrive}:"
}
function Dismount-ISO
{
param ([string] $isoPath)
$isoDrive = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter
if ($isoDrive)
{
Write-Verbose "$isoPath dismounted"
Dismount-DiskImage -ImagePath $isoPath | Out-Null
}
}
function Disable-StrongName
{
param ([string] $publicKeyToken = "*")
reg ADD "HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64")
{
reg ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
}
}
function Test-Admin
{
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal $identity
$principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Test-RegistryPathAndValue
{
param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $path,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $value)
try
{
if (Test-Path $path)
{
Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null
return $true
}
}
catch
{
}
return $false
}
function Test-InstallWindowsSDK
{
$retval = $true
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey)
{
# A Windows SDK is installed
# Is an SDK of our version installed with the options we need?
$allRequiredSdkOptionsInstalled = $true
foreach($sdkOption in $WindowsSDKOptions)
{
if (!(Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value $sdkOption))
{
$allRequiredSdkOptionsInstalled = $false
}
}
if($allRequiredSdkOptionsInstalled)
{
# It appears we have what we need. Double check the disk
$sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey
if ($sdkRoot)
{
if (Test-Path $sdkRoot)
{
$refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion"
if (Test-Path $refPath)
{
$umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion"
if (Test-Path $umdPath)
{
# Pretty sure we have what we need
$retval = $false
}
}
}
}
}
}
return $retval
}
function Test-InstallStrongNameHijack
{
foreach($publicKeyToken in $PublicKeyTokens)
{
$key = "$StrongNameRegPath\*,$publicKeyToken"
if (!(Test-Path $key))
{
return $true
}
}
return $false
}
Write-Host -NoNewline "Checking for installed Windows SDK $WindowsSDKVersion..."
$InstallWindowsSDK = Test-InstallWindowsSDK
if ($InstallWindowsSDK)
{
Write-Host "Installation required"
}
else
{
Write-Host "INSTALLED"
}
$StrongNameHijack = Test-InstallStrongNameHijack
Write-Host -NoNewline "Checking if StrongName bypass required..."
if ($StrongNameHijack)
{
Write-Host "REQUIRED"
}
else
{
Write-Host "Done"
}
if ($StrongNameHijack -or $InstallWindowsSDK)
{
if (!(Test-Admin))
{
Write-Host
throw "ERROR: Elevation required"
}
}
if ($InstallWindowsSDK)
{
# Static(ish) link for Windows SDK
# Note: there is a delay from Windows SDK announcements to availability via the static link
$uri = "https://software-download.microsoft.com/download/sg/Windows_InsiderPreview_SDK_en-us_$($buildNumber)_1.iso";
if ($env:TEMP -eq $null)
{
$env:TEMP = Join-Path $env:SystemDrive 'temp'
}
$winsdkTempDir = Join-Path (Join-Path $env:TEMP ([System.IO.Path]::GetRandomFileName())) "WindowsSDK"
if (![System.IO.Directory]::Exists($winsdkTempDir))
{
[void][System.IO.Directory]::CreateDirectory($winsdkTempDir)
}
$file = "winsdk_$buildNumber.iso"
Write-Verbose "Getting WinSDK from $uri"
$downloadFile = Download-File $winsdkTempDir $uri $file
Write-Verbose "File is at $downloadFile"
$downloadFileItem = Get-Item $downloadFile
# Check to make sure the file is at least 10 MB.
if ($downloadFileItem.Length -lt 10*1024*1024)
{
Write-Host
Write-Host "ERROR: Downloaded file doesn't look large enough to be an ISO. The requested version may not be on microsoft.com yet."
Write-Host
Exit 1
}
# TODO Check if zip, exe, iso, etc.
try
{
Write-Host -NoNewline "Mounting ISO $file..."
Mount-ISO $downloadFile
Write-Host "Done"
$isoDrive = Get-ISODriveLetter $downloadFile
if (Test-Path $isoDrive)
{
Write-Host -NoNewLine "Installing WinSDK..."
$setupPath = Join-Path "$isoDrive" "WinSDKSetup.exe"
Start-Process -Wait $setupPath "/features $WindowsSDKOptions /q"
Write-Host "Done"
}
else
{
throw "Could not find mounted ISO at ${isoDrive}"
}
}
finally
{
Write-Host -NoNewline "Dismounting ISO $file..."
Dismount-ISO $downloadFile
Write-Host "Done"
}
}
if ($StrongNameHijack)
{
Write-Host -NoNewline "Disabling StrongName for Windows SDK..."
foreach($key in $PublicKeyTokens)
{
Disable-StrongName $key
}
Write-Host "Done"
}

View File

@@ -0,0 +1,14 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
Param(
[string]$NewWindowsVersion = "10.0.22000.0"
)
Get-ChildItem src/cascadia/CascadiaPackage -Recurse -Filter *.appxmanifest | ForEach-Object {
$xml = [xml](Get-Content $_.FullName)
$xml.Package.Dependencies.TargetDeviceFamily | Where-Object Name -Like "Windows*" | ForEach-Object {
$_.MinVersion = $NewWindowsVersion
}
$xml.Save($_.FullName)
}

View File

@@ -10,4 +10,18 @@
<OpenConsoleDir>$(MSBuildThisFileDirectory)</OpenConsoleDir>
</PropertyGroup>
<PropertyGroup>
<!--
For the Windows 10 build, we're targeting the prerelease version of Microsoft.UI.Xaml.
This version emits every XAML DLL directly into our package.
This is a workaround for us not having deliverable MSFT-21242953 on this version of Windows.
-->
<TerminalMUXVersion>2.7.2-prerelease.220406002</TerminalMUXVersion>
<!--
For the Windows 11-specific build, we're targeting the public version of Microsoft.UI.Xaml.
This version emits a package dependency instead of embedding the dependency in our own package.
-->
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.1</TerminalMUXVersion>
</PropertyGroup>
</Project>

View File

@@ -2,6 +2,18 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This file is read by XES, which we use in our Release builds. -->
<PropertyGroup Label="Version">
<!--
The Windows 11 build is going to have the same package name, so it *must* have a different version.
The easiest way for us to do this is to add 1 to the revision field.
In short, for a given Terminal build 1.11, we will emit two different versions (assume this is build
4 on day 23 of the year):
- 1.11.234.0 for Windows 10
- 1.11.235.0 for Windows 11
This presents a potential for conflicts if we want to ship two builds produced back to back on the
same day... which is terribly unlikely.
-->
<VersionBuildRevision Condition="'$(TerminalTargetWindowsVersion)'=='Win11' and '$(VersionBuildRevision)'!=''">$([MSBuild]::Add($(VersionBuildRevision), 1))</VersionBuildRevision>
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2021</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>

View File

@@ -189,7 +189,7 @@ I think there might be a bit of a misunderstanding here - there are two differen
* shell applications, like `cmd.exe`, `powershell`, `zsh`, etc. These are text-only applications that emit streams of characters. They don't care at all about how they're eventually rendered to the user. These are also sometimes referred to as "commandline client" applications.
* terminal applications, like the Windows Terminal, gnome-terminal, xterm, iterm2, hyper. These are graphical applications that can be used to render the output of commandline clients.
On Windows, if you just run `cmd.exe` directly, the OS will create an instance of `conhost.exe` as the _terminal_ for `cmd.exe`. The same thing happens for `powershell.exe`, the system will creates a new conhost window for any client that's not already connected to a terminal of some sort. This has lead to an enormous amount of confusion for people thinking that a conhost window is actually a "`cmd` window". `cmd` can't have a window, it's just a commandline application. Its window is always some other terminal.
On Windows, if you just run `cmd.exe` directly, the OS will create an instance of `conhost.exe` as the _terminal_ for `cmd.exe`. The same thing happens for `powershell.exe`, the system will create a new conhost window for any client that's not already connected to a terminal of some sort. This has lead to an enormous amount of confusion for people thinking that a conhost window is actually a "`cmd` window". `cmd` can't have a window, it's just a commandline application. Its window is always some other terminal.
Any terminal can run any commandline client application. So you can use the Windows Terminal to run whatever shell you want. I use mine for both `cmd` and `powershell`, and also WSL:

View File

@@ -15,7 +15,7 @@ Import-Module .\tools\OpenConsole.psm1
Set-MsBuildDevEnvironment
Get-Format
```
After, go to Tools > Options > Text Editor > C++ > Formatting and checking "Use custom clang-format.exe file" in Visual Studio and choose the clang-format.exe in the repository at /packages/clang-format.win-x86.10.0.0/tools/clang-format.exe by clicking "browse" right under the check box.
After, go to Tools > Options > Text Editor > C++ > Formatting and check "Use custom clang-format.exe file" in Visual Studio and choose the clang-format.exe in the repository at /packages/clang-format.win-x86.10.0.0/tools/clang-format.exe by clicking "browse" right under the check box.
### Building in PowerShell

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
---
author: Carlos Zamora @carlos-zamora
created on: 2019-08-30
last updated: 2021-09-17
issue id: 715
---
# Keyboard Selection
## Abstract
This spec describes a new set of non-configurable keybindings that allows the user to update a selection without the use of a mouse or stylus.
## Inspiration
ConHost allows the user to modify a selection using the keyboard. Holding `Shift` allows the user to move the second selection endpoint in accordance with the arrow keys. The selection endpoint updates by one cell per key event, allowing the user to refine the selected region.
Mark mode allows the user to create a selection using only the keyboard, then edit it as mentioned above.
## Solution Design
The fundamental solution design for keyboard selection is that the responsibilities between the Terminal Control and Terminal Core must be very distinct. The Terminal Control is responsible for handling user interaction and directing the Terminal Core to update the selection. The Terminal Core will need to update the selection according to the preferences of the Terminal Control.
Relatively recently, TerminalControl was split into `TerminalControl`, `ControlInteractivity`, and `ControlCore`. Changes made to `ControlInteractivity`, `ControlCore`, and below propagate functionality to all consumers, meaning that the WPF terminal would benefit from these changes with no additional work required.
### Fundamental Terminal Control Changes
`ControlCore::TrySendKeyEvent()` is responsible for handling the key events after key bindings are dealt with in `TermControl`. At the time of writing this spec, there are 2 cases handled in this order:
- Clear the selection (except in a few key scenarios)
- Send Key Event
The first branch will be updated to _modify_ the selection instead of usually _clearing_ it. This will happen by converting the key event into parameters to forward to `TerminalCore`, which then updates the selection appropriately.
#### Idea: Make keyboard selection a collection of standard keybindings
One idea is to introduce an `updateSelection` action that conditionally works if a selection is active (similar to the `copy` action). For these key bindings, if there is no selection, the key events are forwarded to the application.
Thanks to Keybinding Args, there would only be 1 new command:
| Action | Keybinding Args | Description |
|--|--|--|
| `updateSelection` | | If a selection exists, moves the last selection endpoint. |
| | `Enum direction { up, down, left, right }` | The direction the selection will be moved in. |
| | `Enum mode { char, word, view, buffer }` | The context for which to move the selection endpoint to. (defaults to `char`) |
By default, the following keybindings will be set:
```JS
// Character Selection
{ "command": {"action": "updateSelection", "direction": "left", "mode": "char" }, "keys": "shift+left" },
{ "command": {"action": "updateSelection", "direction": "right", "mode": "char" }, "keys": "shift+right" },
{ "command": {"action": "updateSelection", "direction": "up", "mode": "char" }, "keys": "shift+up" },
{ "command": {"action": "updateSelection", "direction": "down", "mode": "char" }, "keys": "shift+down" },
// Word Selection
{ "command": {"action": "updateSelection", "direction": "left", "mode": "word" }, "keys": "ctrl+shift+left" },
{ "command": {"action": "updateSelection", "direction": "right", "mode": "word" }, "keys": "ctrl+shift+right" },
// Viewport Selection
{ "command": {"action": "updateSelection", "direction": "left", "mode": "view" }, "keys": "shift+home" },
{ "command": {"action": "updateSelection", "direction": "right", "mode": "view" }, "keys": "shift+end" },
{ "command": {"action": "updateSelection", "direction": "up", "mode": "view" }, "keys": "shift+pgup" },
{ "command": {"action": "updateSelection", "direction": "down", "mode": "view" }, "keys": "shift+pgdn" },
// Buffer Corner Selection
{ "command": {"action": "updateSelection", "direction": "up", "mode": "buffer" }, "keys": "ctrl+shift+home" },
{ "command": {"action": "updateSelection", "direction": "down", "mode": "buffer" }, "keys": "ctrl+shift+end" },
```
These are in accordance with ConHost's keyboard selection model.
This idea was abandoned due to several reasons:
1. Keyboard selection should be a standard way to interact with a terminal across all consumers (i.e. WPF control, etc.)
2. There isn't really another set of key bindings that makes sense for this. We already hardcoded <kbd>ESC</kbd> as a way to clear the selection. This is just an extension of that.
3. Adding 12 conditionally effective key bindings takes the spot of 12 potential non-conditional key bindings. It would be nice if a different key binding could be set when the selection is not active, but that makes the settings design much more complicated.
4. 12 new items in the command palette is also pretty excessive.
5. If proven wrong when this is in WT Preview, we can revisit this and make them customizable then. It's better to add the ability to customize it later than take it away.
#### Idea: Make keyboard selection a simulation of mouse selection
It may seem that some effort can be saved by making the keyboard selection act as a simulation of mouse selection. There is a union of mouse and keyboard activity that can be represented in a single set of selection motion interfaces that are commanded by the TermControl's Mouse/Keyboard handler and adapted into appropriate motions in the Terminal Core.
However, the mouse handler operates by translating a pixel coordinate on the screen to a text buffer coordinate. This would have to be rewritten and the approach was deemed unworthy.
### Fundamental Terminal Core Changes
The Terminal Core will need to expose a `UpdateSelection()` function that is called by the keybinding handler. The following parameters will need to be passed in:
- `enum SelectionDirection`: the direction that the selection endpoint will attempt to move to. Possible values include `Up`, `Down`, `Left`, and `Right`.
- `enum SelectionExpansion`: the selection expansion mode that the selection endpoint will adhere to. Possible values include `Char`, `Word`, `View`, `Buffer`.
#### Moving by Cell
For `SelectionExpansion = Char`, the selection endpoint will be updated according to the buffer's output pattern. For **horizontal movements**, the selection endpoint will attempt to move left or right. If a viewport boundary is hit, the endpoint will wrap appropriately (i.e.: hitting the left boundary moves it to the last cell of the line above it).
For **vertical movements**, the selection endpoint will attempt to move up or down. If a **viewport boundary** is hit and there is a scroll buffer, the endpoint will move and scroll accordingly by a line.
If a **buffer boundary** is hit, the endpoint will not move. In this case, however, the event will still be considered handled.
**NOTE**: An important thing to handle properly in all cases is wide glyphs. The user should not be allowed to select a portion of a wide glyph; it should be all or none of it. When calling `_ExpandWideGlyphSelection` functions, the result must be saved to the endpoint.
#### Moving by Word
For `SelectionExpansion = Word`, the selection endpoint will also be updated according to the buffer's output pattern, as above. However, the selection will be updated in accordance with "chunk selection" (performing a double-click and dragging the mouse to expand the selection). For **horizontal movements**, the selection endpoint will be updated according to the `_ExpandDoubleClickSelection` functions. The result must be saved to the endpoint. As before, if a boundary is hit, the endpoint will wrap appropriately. See [Future Considerations](#FutureConsiderations) for how this will interact with line wrapping.
For **vertical movements**, the movement is a little more complicated than before. The selection will still respond to buffer and viewport boundaries as before. If the user is trying to move up, the selection endpoint will attempt to move up by one line, then selection will be expanded leftwards. Alternatively, if the user is trying to move down, the selection endpoint will attempt to move down by one line, then the selection will be expanded rightwards.
#### Moving by Viewport
For `SelectionExpansion = View`, the selection endpoint will be updated according to the viewport's height. Horizontal movements will be updated according to the viewport's width, thus resulting in the endpoint being moved to the left/right boundary of the viewport.
#### Moving by Buffer
For `SelectionExpansion = Buffer`, the selection endpoint will be moved to the beginning or end of all the text within the buffer. If moving up or left, set the position to 0,0 (the origin of the buffer). If moving down or right, set the position to the last character in the buffer.
**NOTE**: In all cases, horizontal movements attempting to move past the left/right viewport boundaries result in a wrap. Vertical movements attempting to move past the top/bottom viewport boundaries will scroll such that the selection is at the edge of the screen. Vertical movements attempting to move past the top/bottom buffer boundaries will be clamped to be within buffer boundaries.
Every combination of the `SelectionDirection` and `SelectionExpansion` will map to a keybinding. These pairings are shown below in the UI/UX Design --> Keybindings section.
**NOTE**: If `copyOnSelect` is enabled, we need to make sure we **DO NOT** update the clipboard on every change in selection. The user must explicitly choose to copy the selected text from the buffer.
## UI/UX Design
### Key Bindings
There will only be 1 new command that needs to be added:
| Action | Keybinding Args | Description |
|--|--|--|
| `selectAll` | | Select the entire text buffer.
By default, the following key binding will be set:
```JS
{ "command": "selectAll", "keys": "ctrl+shift+a" },
```
## Capabilities
### Accessibility
Using the keyboard is generally a more accessible experience than using the mouse. Being able to modify a selection by using the keyboard is a good first step towards making selecting text more accessible.
### Security
N/A
### Reliability
With regards to the Terminal Core, the newly introduced code should rely on already existing and tested code. Thus no crash-related bugs are expected.
With regards to Terminal Control and the settings model, crash-related bugs are not expected. However, ensuring that the selection is updated and cleared in general use-case scenarios must be ensured.
### Compatibility
N/A
### Performance, Power, and Efficiency
## Potential Issues
### Grapheme Clusters
When grapheme cluster support is inevitably added to the Text Buffer, moving by "cell" is expected to move by "character" or "cluster". This is similar to how wide glyphs are handled today. Either all of it is selected, or none of it.
## Future considerations
### Word Selection Wrap
At the time of writing this spec, expanding or moving by word is interrupted by the beginning or end of the line, regardless of the wrap flag being set. In the future, selection and the accessibility models will respect the wrap flag on the text buffer.
## Mark Mode
This functionality will be expanded to create a feature similar to Mark Mode. This will allow a user to create a selection using only the keyboard.
## Resources
- https://blogs.windows.com/windowsdeveloper/2014/10/07/console-improvements-in-the-windows-10-technical-preview/

201
oss/pcg/LICENSE-APACHE.txt Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

19
oss/pcg/LICENSE-MIT.txt Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
oss/pcg/cgmanifest.json Normal file
View File

@@ -0,0 +1,14 @@
{
"Registrations": [
{
"component": {
"type": "git",
"git": {
"repositoryUrl": "https://github.com/imneme/pcg-cpp",
"commitHash": "ffd522e7188bef30a00c74dc7eb9de5faff90092"
}
}
}
],
"Version": 1
}

View File

@@ -0,0 +1,82 @@
// PCG Random Number Generation for C++
//
// Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>,
// and the PCG Project contributors.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//
// Licensed under the Apache License, Version 2.0 (provided in
// LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
// or under the MIT license (provided in LICENSE-MIT.txt and at
// http://opensource.org/licenses/MIT), at your option. This file may not
// be copied, modified, or distributed except according to those terms.
//
// Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
// express or implied. See your chosen license for details.
//
// For additional information about the PCG random number generation scheme,
// visit http://www.pcg-random.org/.
//
// -----------------------------------------------------------------------------
//
// Leonard Hecker <lhecker@microsoft.com>:
// The following contents are an extract of pcg_engines::oneseq_dxsm_64_32
// reduced down to the bare essentials, while retaining base functionality.
namespace pcg_engines {
class oneseq_dxsm_64_32 {
using xtype = uint32_t;
using itype = uint64_t;
itype state_;
static constexpr uint64_t multiplier() {
return 6364136223846793005ULL;
}
static constexpr uint64_t increment() {
return 1442695040888963407ULL;
}
static itype bump(itype state) {
return state * multiplier() + increment();
}
itype base_generate0() {
itype old_state = state_;
state_ = bump(state_);
return old_state;
}
public:
explicit oneseq_dxsm_64_32(itype state = 0xcafef00dd15ea5e5ULL) : state_(bump(state + increment())) {
}
// Returns a value in the interval [0, UINT32_MAX].
xtype operator()() {
constexpr auto xtypebits = uint8_t(sizeof(xtype) * 8);
constexpr auto itypebits = uint8_t(sizeof(itype) * 8);
auto internal = base_generate0();
auto hi = xtype(internal >> (itypebits - xtypebits));
auto lo = xtype(internal);
lo |= 1;
hi ^= hi >> (xtypebits / 2);
hi *= xtype(multiplier());
hi ^= hi >> (3 * (xtypebits / 4));
hi *= lo;
return hi;
}
// Returns a value in the interval [0, upper_bound).
xtype operator()(xtype upper_bound) {
uint32_t threshold = (UINT64_MAX + uint32_t(1) - upper_bound) % upper_bound;
for (;;) {
auto r = operator()();
if (r >= threshold)
return r % upper_bound;
}
}
};
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -8,5 +8,5 @@ Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadi
### Fonts Included
* Cascadia Code, Cascadia Mono (2108.26)
* from microsoft/cascadia-code@f91d08f703ee61cf4ae936b9700ca974de2748fe
* Cascadia Code, Cascadia Mono (2111.01)
* from microsoft/cascadia-code@de36d62e777d34d3bed92a7e23988e5d61e0ba02

View File

@@ -140,12 +140,12 @@
<!-- **END VC LIBS HACK** -->
<!-- This is required to get the package dependency in the AppXManifest. -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>

View File

@@ -45,7 +45,7 @@ namespace winrt::SampleApp::implementation
WINRT_PROPERTY(winrt::hstring, ProfileName);
WINRT_PROPERTY(bool, UseAcrylic, false);
WINRT_PROPERTY(double, TintOpacity, 0.5);
WINRT_PROPERTY(double, Opacity, .5);
WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas");
WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE);

View File

@@ -147,13 +147,13 @@
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target>

View File

@@ -80,13 +80,13 @@
</ItemGroup>
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.7.1" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
</packages>

View File

@@ -120,14 +120,14 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.7.1" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
</packages>

View File

@@ -12,6 +12,16 @@
<EventProvider Id="EventProvider_TerminalWin32Host" Name="56c06166-2e2e-5f4d-7ff3-74f4b78c87d6" />
<EventProvider Id="EventProvider_TerminalRemoting" Name="d6f04aad-629f-539a-77c1-73f5c3e4aa7b" />
<EventProvider Id="EventProvider_TerminalDirectX" Name="c93e739e-ae50-5a14-78e7-f171e947535d" />
<EventProvider Id="EventProvider_TerminalUIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
<!-- Console providers here -->
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Launcher" Name="770aa552-671a-5e97-579b-151709ec0dbd"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Host" Name="fe1ff234-1f09-50a8-d38d-c44fab43e818"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Server" Name="1A541C01-589A-496E-85A7-A9E02170166D"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.VirtualTerminal.Parser" Name="c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Render.VtEngine" Name="c9ba2a95-d3ca-5e19-2bd6-776a0910cb9d"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.UIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
<!-- Profile for General Terminal logging -->
<Profile Id="Terminal.Verbose.File" Name="Terminal" Description="Terminal" LoggingMode="File" DetailLevel="Verbose">
<Collectors>
<EventCollectorId Value="EventCollector_Terminal">
@@ -23,6 +33,7 @@
<EventProviderId Value="EventProvider_TerminalWin32Host" />
<EventProviderId Value="EventProvider_TerminalRemoting" />
<EventProviderId Value="EventProvider_TerminalDirectX" />
<EventProviderId Value="EventProvider_TerminalUIA" />
</EventProviders>
</EventCollectorId>
</Collectors>
@@ -30,5 +41,27 @@
<Profile Id="Terminal.Light.File" Name="Terminal" Description="Terminal" Base="Terminal.Verbose.File" LoggingMode="File" DetailLevel="Light" />
<Profile Id="Terminal.Verbose.Memory" Name="Terminal" Description="Terminal" Base="Terminal.Verbose.File" LoggingMode="Memory" DetailLevel="Verbose" />
<Profile Id="Terminal.Light.Memory" Name="Terminal" Description="Terminal" Base="Terminal.Verbose.File" LoggingMode="Memory" DetailLevel="Light" />
<!-- Profile for DefTerm logging. Includes some conhost logging. -->
<Profile Id="DefTerm.Verbose.File" Name="DefTerm" Description="DefTerm" LoggingMode="File" DetailLevel="Verbose">
<Collectors>
<EventCollectorId Value="EventCollector_Terminal">
<EventProviders>
<EventProviderId Value="EventProvider_TerminalControl" />
<EventProviderId Value="EventProvider_TerminalConnection" />
<EventProviderId Value="EventProvider_TerminalSettingsModel" />
<EventProviderId Value="EventProvider_TerminalApp" />
<EventProviderId Value="EventProvider_TerminalWin32Host" />
<EventProviderId Value="EventProvider_TerminalRemoting" />
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Launcher" />
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Host" />
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Server" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="DefTerm.Light.File" Name="DefTerm" Description="DefTerm" Base="DefTerm.Verbose.File" LoggingMode="File" DetailLevel="Light" />
<Profile Id="DefTerm.Verbose.Memory" Name="DefTerm" Description="DefTerm" Base="DefTerm.Verbose.File" LoggingMode="Memory" DetailLevel="Verbose" />
<Profile Id="DefTerm.Light.Memory" Name="DefTerm" Description="DefTerm" Base="DefTerm.Verbose.File" LoggingMode="Memory" DetailLevel="Light" />
</Profiles>
</WindowsPerformanceRecorder>
</WindowsPerformanceRecorder>

View File

@@ -97,14 +97,14 @@ OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text) :
// Arguments:
// - utf16Text - UTF-16 text range
// - attribute - Color to apply over the entire range
OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute) :
OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute& attribute, const size_t fillLimit) :
_mode(Mode::Loose),
_currentView(s_GenerateView(utf16Text, attribute)),
_run(utf16Text),
_attr(attribute),
_distance(0),
_pos(0),
_fillLimit(0)
_fillLimit(fillLimit)
{
}

View File

@@ -38,7 +38,7 @@ public:
OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const std::wstring_view utf16Text);
OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute);
OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute& attribute, const size_t fillLimit = 0);
OutputCellIterator(const gsl::span<const WORD> legacyAttributes) noexcept;
OutputCellIterator(const gsl::span<const CHAR_INFO> charInfos) noexcept;
OutputCellIterator(const gsl::span<const OutputCell> cells);

View File

@@ -4,6 +4,8 @@
#include "precomp.h"
#include "TextColor.h"
#include <til/bit.h>
// clang-format off
// A table mapping 8-bit RGB colors, in the form RRRGGGBB,
@@ -186,7 +188,7 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
// the result will be something like 0b00100000.
// 5. Use BitScanForward (bsf) to find the index of the most significant 1 bit.
const auto haystack = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(colorTable.data())); // 1.
const auto needle = _mm256_set1_epi32(__builtin_bit_cast(int, defaultColor)); // 2.
const auto needle = _mm256_set1_epi32(til::bit_cast<int>(defaultColor)); // 2.
const auto result = _mm256_cmpeq_epi32(haystack, needle); // 3.
const auto mask = _mm256_movemask_ps(_mm256_castsi256_ps(result)); // 4.
unsigned long index;
@@ -203,7 +205,7 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
// --> the index returned by _BitScanForward must be divided by 2.
const auto haystack1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 0));
const auto haystack2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 4));
const auto needle = _mm_set1_epi32(__builtin_bit_cast(int, defaultColor));
const auto needle = _mm_set1_epi32(til::bit_cast<int>(defaultColor));
const auto result1 = _mm_cmpeq_epi32(haystack1, needle);
const auto result2 = _mm_cmpeq_epi32(haystack2, needle);
const auto result = _mm_packs_epi32(result1, result2); // 3.5

View File

@@ -8,8 +8,11 @@
#include "../types/inc/utils.hpp"
#include "../types/inc/convert.hpp"
#include "../../types/inc/Utf16Parser.hpp"
#include "../../types/inc/GlyphWidth.hpp"
#include <til/bit.h>
#pragma hdrstop
using namespace Microsoft::Console;
@@ -1057,9 +1060,10 @@ const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std
// - accessibilityMode - when enabled, we continue expanding left until we are at the beginning of a readable word.
// Otherwise, expand left until a character of a new delimiter class is found
// (or a row boundary is encountered)
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - The COORD for the first character on the "word" (inclusive)
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
{
// Consider a buffer with this text in it:
// " word other "
@@ -1072,10 +1076,9 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
// NOTE: the start anchor (this one) is inclusive, whereas the end anchor (GetWordEnd) is exclusive
#pragma warning(suppress : 26496)
// GH#7664: Treat EndExclusive as EndInclusive so
// that it actually points to a space in the buffer
auto copy{ target };
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (target == bufferSize.Origin())
{
// can't expand left
@@ -1083,9 +1086,15 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
}
else if (target == bufferSize.EndExclusive())
{
// treat EndExclusive as EndInclusive
// GH#7664: Treat EndExclusive as EndInclusive so
// that it actually points to a space in the buffer
copy = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() };
}
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
// if at/past the limit --> clamp to limit
copy = *limitOptional;
}
if (accessibilityMode)
{
@@ -1179,9 +1188,10 @@ const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std:
// - accessibilityMode - when enabled, we continue expanding right until we are at the beginning of the next READABLE word
// Otherwise, expand right until a character of a new delimiter class is found
// (or a row boundary is encountered)
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - The COORD for the last character on the "word" (inclusive)
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
{
// Consider a buffer with this text in it:
// " word other "
@@ -1193,16 +1203,17 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
// so the words in the example include ["word ", "other "]
// NOTE: the end anchor (this one) is exclusive, whereas the start anchor (GetWordStart) is inclusive
// Already at the end. Can't move forward.
if (target == GetSize().EndExclusive())
// Already at/past the limit. Can't move forward.
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
return target;
}
if (accessibilityMode)
{
const auto lastCharPos{ GetLastNonSpaceCharacter() };
return _GetWordEndForAccessibility(target, wordDelimiters, lastCharPos);
return _GetWordEndForAccessibility(target, wordDelimiters, limit);
}
else
{
@@ -1215,44 +1226,46 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
// Arguments:
// - target - a COORD on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// - lastCharPos - the position of the last nonspace character in the text buffer (to improve performance)
// - limit - the last "valid" position in the text buffer (to improve performance)
// Return Value:
// - The COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const
{
const auto bufferSize = GetSize();
COORD result = target;
const auto bufferSize{ GetSize() };
COORD result{ target };
// Check if we're already on/past the last RegularChar
if (bufferSize.CompareInBounds(result, lastCharPos, true) >= 0)
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
return bufferSize.EndExclusive();
// if we're already on/past the last RegularChar,
// clamp result to that position
result = limit;
// make the result exclusive
bufferSize.IncrementInBounds(result, true);
}
// ignore right boundary. Continue through readable text found
while (_GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
else
{
if (!bufferSize.IncrementInBounds(result, true))
auto iter{ GetCellDataAt(result, bufferSize) };
while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) == DelimiterClass::RegularChar)
{
break;
// Iterate through readable text
++iter;
}
}
// we are already on/past the last RegularChar
if (bufferSize.CompareInBounds(result, lastCharPos, true) >= 0)
{
return bufferSize.EndExclusive();
}
// make sure we expand to the beginning of the NEXT word
while (_GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
{
if (!bufferSize.IncrementInBounds(result, true))
while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) != DelimiterClass::RegularChar)
{
// we are at the EndInclusive COORD
// this signifies that we must include the last char in the buffer
// but the position of the COORD points to nothing
break;
// expand to the beginning of the NEXT word
++iter;
}
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 (!iter)
{
bufferSize.IncrementInBounds(result, true);
}
}
@@ -1345,18 +1358,20 @@ void TextBuffer::_PruneHyperlinks()
// Arguments:
// - pos - a COORD on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// - lastCharPos - the position of the last nonspace character in the text buffer (to improve performance)
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first character on the "word" (inclusive)
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional) const
{
// move to the beginning of the next word
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
// This is also the inclusive start of the next word.
auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, lastCharPos) };
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
if (copy == GetSize().EndExclusive())
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
{
return false;
}
@@ -1393,19 +1408,23 @@ bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters
// - Update pos to be the beginning of the current glyph/character. This is used for accessibility
// Arguments:
// - pos - a COORD on the word you are currently on
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - pos - The COORD for the first cell of the current glyph (inclusive)
const til::point TextBuffer::GetGlyphStart(const til::point pos) const
const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional) const
{
COORD resultPos = pos;
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (resultPos == bufferSize.EndExclusive())
// Clamp pos to limit
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
{
bufferSize.DecrementInBounds(resultPos, true);
resultPos = limit;
}
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
// limit is exclusive, so we need to move back to be within valid bounds
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
{
bufferSize.DecrementInBounds(resultPos, true);
}
@@ -1414,23 +1433,34 @@ const til::point TextBuffer::GetGlyphStart(const til::point pos) const
}
// Method Description:
// - Update pos to be the end of the current glyph/character. This is used for accessibility
// - Update pos to be the end of the current glyph/character.
// Arguments:
// - pos - a COORD on the word you are currently on
// - accessibilityMode - this is being used for accessibility; make the end exclusive.
// Return Value:
// - pos - The COORD for the last cell of the current glyph (exclusive)
const til::point TextBuffer::GetGlyphEnd(const til::point pos) const
const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode, std::optional<til::point> limitOptional) const
{
COORD resultPos = pos;
const auto bufferSize = GetSize();
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
// Clamp pos to limit
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
{
resultPos = limit;
}
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
{
bufferSize.IncrementInBounds(resultPos, true);
}
// increment one more time to become exclusive
bufferSize.IncrementInBounds(resultPos, true);
if (accessibilityMode)
{
bufferSize.IncrementInBounds(resultPos, true);
}
return resultPos;
}
@@ -1438,29 +1468,43 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos) const
// - Update pos to be the beginning of the next glyph/character. This is used for accessibility
// Arguments:
// - pos - a COORD on the word you are currently on
// - allowBottomExclusive - allow the nonexistent end-of-buffer cell to be encountered
// - allowExclusiveEnd - allow result to be the exclusive limit (one past limit)
// - limit - boundaries for the iterator to operate within
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first cell of the current glyph (inclusive)
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowBottomExclusive) const
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional<til::point> limitOptional) const
{
COORD resultPos = pos;
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (resultPos == GetSize().EndExclusive())
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) };
if (distanceToLimit >= 0)
{
// we're already at the end
// Corner Case: we're on/past the limit
// Clamp us to the limit
pos = limit;
return false;
}
else if (!allowExclusiveEnd && distanceToLimit == -1)
{
// Corner Case: we're just before the limit
// and we are not allowed onto the exclusive end.
// Fail to move.
return false;
}
// try to move. If we can't, we're done.
const bool success = bufferSize.IncrementInBounds(resultPos, allowBottomExclusive);
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
// Try to move forward, but if we hit the buffer boundary, we fail to move.
auto iter{ GetCellDataAt(pos, bufferSize) };
const bool success{ ++iter };
// Move again if we're on a wide glyph
if (success && iter->DbcsAttr().IsTrailing())
{
bufferSize.IncrementInBounds(resultPos, allowBottomExclusive);
++iter;
}
pos = resultPos;
pos = iter.Pos();
return success;
}
@@ -1471,12 +1515,21 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowBottomExclusive) con
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first cell of the previous glyph (inclusive)
bool TextBuffer::MoveToPreviousGlyph(til::point& pos) const
bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point> limitOptional) const
{
COORD resultPos = pos;
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (bufferSize.CompareInBounds(pos, limit, true) > 0)
{
// we're past the end
// clamp us to the limit
pos = limit;
return true;
}
// try to move. If we can't, we're done.
const auto bufferSize = GetSize();
const bool success = bufferSize.DecrementInBounds(resultPos, true);
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
{
@@ -1983,20 +2036,8 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
const auto writeAccumulatedChars = [&](bool includeCurrent) {
if (col >= startOffset)
{
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
for (const auto c : unescapedText)
{
switch (c)
{
case '\\':
case '{':
case '}':
contentBuilder << "\\" << c;
break;
default:
contentBuilder << c;
}
}
const auto text = std::wstring_view{ rows.text.at(row) }.substr(startOffset, col - startOffset + includeCurrent);
_AppendRTFText(contentBuilder, text);
startOffset = col;
}
@@ -2095,6 +2136,31 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
}
}
void TextBuffer::_AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text)
{
for (const auto codeUnit : text)
{
if (codeUnit <= 127)
{
switch (codeUnit)
{
case L'\\':
case L'{':
case L'}':
contentBuilder << "\\" << gsl::narrow<char>(codeUnit);
break;
default:
contentBuilder << gsl::narrow<char>(codeUnit);
}
}
else
{
// Windows uses unsigned wchar_t - RTF uses signed ones.
contentBuilder << "\\u" << std::to_string(til::bit_cast<int16_t>(codeUnit)) << "?";
}
}
}
// Function Description:
// - Reflow the contents from the old buffer into the new buffer. The new buffer
// can have different dimensions than the old buffer. If it does, then this
@@ -2133,7 +2199,8 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
bool foundOldVisible = false;
HRESULT hr = S_OK;
// Loop through all the rows of the old buffer and reprint them into the new buffer
for (short iOldRow = 0; iOldRow < cOldRowsTotal; iOldRow++)
short iOldRow = 0;
for (; iOldRow < cOldRowsTotal; iOldRow++)
{
// Fetch the row and its "right" which is the last printable character.
const ROW& row = oldBuffer.GetRowByOffset(iOldRow);
@@ -2177,7 +2244,9 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
// Loop through every character in the current row (up to
// the "right" boundary, which is one past the final valid
// character)
for (short iOldCol = 0; iOldCol < iRight; iOldCol++)
short iOldCol = 0;
const auto copyRight = iRight;
for (; iOldCol < copyRight; iOldCol++)
{
if (iOldCol == cOldCursorPos.X && iOldRow == cOldCursorPos.Y)
{
@@ -2201,6 +2270,48 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
CATCH_RETURN();
}
// GH#32: Copy the attributes from the rest of the row into this new buffer.
// From where we are in the old buffer, to the end of the row, copy the
// remaining attributes.
// - if the old buffer is smaller than the new buffer, then just copy
// what we have, as it was. We already copied all _text_ with colors,
// but it's possible for someone to just put some color into the
// buffer to the right of that without any text (as just spaces). The
// buffer looks weird to the user when we resize and it starts losing
// those colors, so we need to copy them over too... as long as there
// is space. The last attr in the row will be extended to the end of
// the row in the new buffer.
// - if the old buffer is WIDER, than we might have wrapped onto a new
// line. Use the cursor's position's Y so that we know where the new
// row is, and start writing at the cursor position. Again, the attr
// in the last column of the old row will be extended to the end of the
// row that the text was flowed onto.
// - if the text in the old buffer didn't actually fill the whole
// line in the new buffer, then we didn't wrap. That's fine. just
// copy attributes from the old row till the end of the new row, and
// move on.
const auto newRowY = newCursor.GetPosition().Y;
auto& newRow = newBuffer.GetRowByOffset(newRowY);
auto newAttrColumn = newCursor.GetPosition().X;
const auto newWidth = newBuffer.GetLineWidth(newRowY);
// Stop when we get to the end of the buffer width, or the new position
// for inserting an attr would be past the right of the new buffer.
for (short copyAttrCol = iOldCol;
copyAttrCol < cOldColsTotal && newAttrColumn < newWidth;
copyAttrCol++, newAttrColumn++)
{
try
{
// TODO: MSFT: 19446208 - this should just use an iterator and the inserter...
const auto textAttr = row.GetAttrRow().GetAttrByColumn(copyAttrCol);
if (!newRow.GetAttrRow().SetAttrToEnd(newAttrColumn, textAttr))
{
break;
}
}
CATCH_LOG(); // Not worth dying over.
}
// If we found the old row that the caller was interested in, set the
// out value of that parameter to the cursor's current Y position (the
// new location of the _end_ of that row in the buffer).
@@ -2234,7 +2345,7 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
// only because we ran out of space.
if (iRight < cOldColsTotal && !row.WasWrapForced())
{
if (iRight == cOldCursorPos.X && iOldRow == cOldCursorPos.Y)
if (!fFoundCursorPos && (iRight == cOldCursorPos.X && iOldRow == cOldCursorPos.Y))
{
cNewCursorPos = newCursor.GetPosition();
fFoundCursorPos = true;
@@ -2285,6 +2396,34 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
}
}
}
// Finish copying buffer attributes to remaining rows below the last
// printable character. This is to fix the `color 2f` scenario, where you
// change the buffer colors then resize and everything below the last
// printable char gets reset. See GH #12567
auto newRowY = newCursor.GetPosition().Y + 1;
const auto newHeight = newBuffer.GetSize().Height();
const auto oldHeight = oldBuffer.GetSize().Height();
for (;
iOldRow < oldHeight && newRowY < newHeight;
iOldRow++)
{
const ROW& row = oldBuffer.GetRowByOffset(iOldRow);
// Optimization: Since all these rows are below the last printable char,
// we can reasonably assume that they are filled with just spaces.
// That's convenient, we can just copy the attr row from the old buffer
// into the new one, and resize the row to match. We'll rely on the
// behavior of ATTR_ROW::Resize to trim down when narrower, or extend
// the last attr when wider.
auto& newRow = newBuffer.GetRowByOffset(newRowY);
const auto newWidth = newBuffer.GetLineWidth(newRowY);
newRow.GetAttrRow() = row.GetAttrRow();
newRow.GetAttrRow().Resize(newWidth);
newRowY++;
}
if (SUCCEEDED(hr))
{
// Finish copying remaining parameters from the old text buffer to the new one
@@ -2535,16 +2674,17 @@ PointTree TextBuffer::GetPatterns(const size_t firstRow, const size_t lastRow) c
// match and the previous match, so we use the size of the prefix
// along with the size of the match to determine the locations
size_t prefixSize = 0;
for (const auto ch : i->prefix().str())
for (const std::vector<wchar_t> parsedGlyph : Utf16Parser::Parse(i->prefix().str()))
{
prefixSize += IsGlyphFullWidth(ch) ? 2 : 1;
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
prefixSize += IsGlyphFullWidth(glyph) ? 2 : 1;
}
const auto start = lenUpToThis + prefixSize;
size_t matchSize = 0;
for (const auto ch : i->str())
for (const std::vector<wchar_t> parsedGlyph : Utf16Parser::Parse(i->str()))
{
matchSize += IsGlyphFullWidth(ch) ? 2 : 1;
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
matchSize += IsGlyphFullWidth(glyph) ? 2 : 1;
}
const auto end = start + matchSize;
lenUpToThis = end;

View File

@@ -141,15 +141,15 @@ public:
Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept;
const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const;
const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const;
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const;
const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const;
const til::point GetGlyphStart(const til::point pos) const;
const til::point GetGlyphEnd(const til::point pos) const;
bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false) const;
bool MoveToPreviousGlyph(til::point& pos) const;
const til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
const til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToPreviousGlyph(til::point& pos, std::optional<til::point> limitOptional = std::nullopt) const;
const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const;
@@ -242,11 +242,13 @@ private:
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const;
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const;
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const;
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const;
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
void _PruneHyperlinks();
static void _AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text);
std::unordered_map<size_t, std::wstring> _idsAndPatterns;
size_t _currentPatternId;

View File

@@ -122,36 +122,34 @@
</ItemGroup>
</Target>
<!-- **BEGIN VC LIBS HACK** -->
<!--
For our release builds, we're just going to integrate the UWPDesktop CRT into our package and delete the package dependencies.
It's very difficult for users who do not have access to the store to get our dependency packages, and we want to be robust
and deployable everywhere. Since these libraries can be redistributed, it's easiest if we simply redistribute them.
See also the "VC LIBS HACK" section in WindowsTerminal.vcxproj.
Some of our dependencies still require a CRT, so we're going to ship the forwarders in our package and
depend on the desktop CRT. This lets us unify the Windows 10 and Windows 11 builds around a common CRT.
-->
<!-- This target removes the FrameworkSdkReferences from before the AppX package targets manifest generation happens.
This is part of the generic machinery that applies to every AppX. -->
<Target Name="_OpenConsoleStripAllDependenciesFromPackageFirstManifest" BeforeTargets="_GenerateCurrentProjectAppxManifest">
<ItemGroup Condition="'$(WindowsTerminalOfficialBuild)'=='true'">
<FrameworkSdkReference Remove="@(FrameworkSdkReference)" />
<ItemGroup>
<FrameworkSdkReference Remove="@(FrameworkSdkReference)" Condition="'%(FrameworkSdkReference.SimpleName)'=='Microsoft.VCLibs'" />
<FrameworkSdkPackage Remove="@(FrameworkSdkPackage)" Condition="'%(FrameworkSdkPackage.Name)'=='Microsoft.VCLibs.140.00' or '%(FrameworkSdkPackage.Name)'=='Microsoft.VCLibs.140.00.Debug'" />
</ItemGroup>
</Target>
<!-- This target removes the FrameworkSdkPackages from before the *desktop bridge* manifest generation happens. -->
<Target Name="_OpenConsoleStripAllDependenciesFromPackageSecondManifest" BeforeTargets="_GenerateDesktopBridgeAppxManifest" DependsOnTargets="_ResolveVCLibDependencies">
<ItemGroup Condition="'$(WindowsTerminalOfficialBuild)'=='true'">
<FrameworkSdkPackage Remove="@(FrameworkSdkPackage)" />
<ItemGroup>
<FrameworkSdkReference Remove="@(FrameworkSdkReference)" Condition="'%(FrameworkSdkReference.SimpleName)'=='Microsoft.VCLibs'" />
<FrameworkSdkPackage Remove="@(FrameworkSdkPackage)" Condition="'%(FrameworkSdkPackage.Name)'=='Microsoft.VCLibs.140.00' or '%(FrameworkSdkPackage.Name)'=='Microsoft.VCLibs.140.00.Debug'" />
</ItemGroup>
</Target>
<!-- **END VC LIBS HACK** -->
<!-- This is required to get the package dependency in the AppXManifest. -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />

View File

@@ -20,17 +20,17 @@
Version="0.0.1.0" />
<Properties>
<DisplayName>Windows Terminal Dev</DisplayName>
<DisplayName>ms-resource:AppStoreNameDev</DisplayName>
<PublisherDisplayName>A Lone Developer</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
<Resource Language="EN-US" />
</Resources>
<Applications>
@@ -87,7 +87,7 @@
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.terminal.host"
Id="Terminal-Dev"
DisplayName="Windows Terminal Dev"
DisplayName="Terminal Dev"
Description="Terminal host built from microsoft/terminal open source repository"
PublicFolder="Public">
<uap3:Properties>

View File

@@ -21,17 +21,105 @@
Version="0.5.0.0" />
<Properties>
<DisplayName>Windows Terminal Preview</DisplayName>
<DisplayName>ms-resource:AppStoreNamePre</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
<Resource Language="EN-US" />
<Resource Language="EN-GB" />
<Resource Language="AF-ZA" />
<Resource Language="AM-ET" />
<Resource Language="AR-SA" />
<Resource Language="AS-IN" />
<Resource Language="AZ-LATN-AZ" />
<Resource Language="BG-BG" />
<Resource Language="BN-IN" />
<Resource Language="BS-LATN-BA" />
<Resource Language="CA-ES" />
<Resource Language="CA-ES-VALENCIA" />
<Resource Language="CS-CZ" />
<Resource Language="CY-GB" />
<Resource Language="DA-DK" />
<Resource Language="DE-DE" />
<Resource Language="EL-GR" />
<Resource Language="ES-ES" />
<Resource Language="ES-MX" />
<Resource Language="ET-EE" />
<Resource Language="EU-ES" />
<Resource Language="FA-IR" />
<Resource Language="FI-FI" />
<Resource Language="FIL-PH" />
<Resource Language="FR-CA" />
<Resource Language="FR-FR" />
<Resource Language="GA-IE" />
<Resource Language="GD-GB" />
<Resource Language="GL-ES" />
<Resource Language="GU-IN" />
<Resource Language="HE-IL" />
<Resource Language="HI-IN" />
<Resource Language="HR-HR" />
<Resource Language="HU-HU" />
<Resource Language="HY-AM" />
<Resource Language="ID-ID" />
<Resource Language="IS-IS" />
<Resource Language="IT-IT" />
<Resource Language="JA-JP" />
<Resource Language="KA-GE" />
<Resource Language="KK-KZ" />
<Resource Language="KM-KH" />
<Resource Language="KN-IN" />
<Resource Language="KO-KR" />
<Resource Language="KOK-IN" />
<Resource Language="LB-LU" />
<Resource Language="LO-LA" />
<Resource Language="LT-LT" />
<Resource Language="LV-LV" />
<Resource Language="MI-NZ" />
<Resource Language="MK-MK" />
<Resource Language="ML-IN" />
<Resource Language="MR-IN" />
<Resource Language="MS-MY" />
<Resource Language="MT-MT" />
<Resource Language="NB-NO" />
<Resource Language="NE-NP" />
<Resource Language="NL-NL" />
<Resource Language="NN-NO" />
<Resource Language="OR-IN" />
<Resource Language="PA-IN" />
<Resource Language="PL-PL" />
<Resource Language="PT-BR" />
<Resource Language="PT-PT" />
<Resource Language="QPS-PLOC" />
<Resource Language="QPS-PLOCA" />
<Resource Language="QPS-PLOCM" />
<Resource Language="QUZ-PE" />
<Resource Language="RO-RO" />
<Resource Language="RU-RU" />
<Resource Language="SK-SK" />
<Resource Language="SL-SI" />
<Resource Language="SQ-AL" />
<Resource Language="SR-CYRL-BA" />
<Resource Language="SR-CYRL-RS" />
<Resource Language="SR-LATN-RS" />
<Resource Language="SV-SE" />
<Resource Language="TA-IN" />
<Resource Language="TE-IN" />
<Resource Language="TH-TH" />
<Resource Language="TR-TR" />
<Resource Language="TT-RU" />
<Resource Language="UG-CN" />
<Resource Language="UK-UA" />
<Resource Language="UR-PK" />
<Resource Language="UZ-LATN-UZ" />
<Resource Language="VI-VN" />
<Resource Language="ZH-CN" />
<Resource Language="ZH-TW" />
</Resources>
<Applications>
@@ -88,7 +176,7 @@
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.terminal.host"
Id="Terminal-Pre"
DisplayName="Windows Terminal Preview"
DisplayName="Terminal Preview"
Description="Terminal host built from microsoft/terminal open source repository"
PublicFolder="Public">
<uap3:Properties>
@@ -147,4 +235,9 @@
</uap7:SharedFonts>
</uap7:Extension>
</Extensions>
<mp:PhoneIdentity
PhoneProductId="43878781-e1d0-4e2e-ae17-c4b63c8fb084"
PhonePublisherId="95d94207-0c7c-47ed-82db-d75c81153c35" />
</Package>

View File

@@ -21,17 +21,105 @@
Version="1.0.0.0" />
<Properties>
<DisplayName>Windows Terminal</DisplayName>
<DisplayName>ms-resource:AppStoreName</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
<Resource Language="EN-US" />
<Resource Language="EN-GB" />
<Resource Language="AF-ZA" />
<Resource Language="AM-ET" />
<Resource Language="AR-SA" />
<Resource Language="AS-IN" />
<Resource Language="AZ-LATN-AZ" />
<Resource Language="BG-BG" />
<Resource Language="BN-IN" />
<Resource Language="BS-LATN-BA" />
<Resource Language="CA-ES" />
<Resource Language="CA-ES-VALENCIA" />
<Resource Language="CS-CZ" />
<Resource Language="CY-GB" />
<Resource Language="DA-DK" />
<Resource Language="DE-DE" />
<Resource Language="EL-GR" />
<Resource Language="ES-ES" />
<Resource Language="ES-MX" />
<Resource Language="ET-EE" />
<Resource Language="EU-ES" />
<Resource Language="FA-IR" />
<Resource Language="FI-FI" />
<Resource Language="FIL-PH" />
<Resource Language="FR-CA" />
<Resource Language="FR-FR" />
<Resource Language="GA-IE" />
<Resource Language="GD-GB" />
<Resource Language="GL-ES" />
<Resource Language="GU-IN" />
<Resource Language="HE-IL" />
<Resource Language="HI-IN" />
<Resource Language="HR-HR" />
<Resource Language="HU-HU" />
<Resource Language="HY-AM" />
<Resource Language="ID-ID" />
<Resource Language="IS-IS" />
<Resource Language="IT-IT" />
<Resource Language="JA-JP" />
<Resource Language="KA-GE" />
<Resource Language="KK-KZ" />
<Resource Language="KM-KH" />
<Resource Language="KN-IN" />
<Resource Language="KO-KR" />
<Resource Language="KOK-IN" />
<Resource Language="LB-LU" />
<Resource Language="LO-LA" />
<Resource Language="LT-LT" />
<Resource Language="LV-LV" />
<Resource Language="MI-NZ" />
<Resource Language="MK-MK" />
<Resource Language="ML-IN" />
<Resource Language="MR-IN" />
<Resource Language="MS-MY" />
<Resource Language="MT-MT" />
<Resource Language="NB-NO" />
<Resource Language="NE-NP" />
<Resource Language="NL-NL" />
<Resource Language="NN-NO" />
<Resource Language="OR-IN" />
<Resource Language="PA-IN" />
<Resource Language="PL-PL" />
<Resource Language="PT-BR" />
<Resource Language="PT-PT" />
<Resource Language="QPS-PLOC" />
<Resource Language="QPS-PLOCA" />
<Resource Language="QPS-PLOCM" />
<Resource Language="QUZ-PE" />
<Resource Language="RO-RO" />
<Resource Language="RU-RU" />
<Resource Language="SK-SK" />
<Resource Language="SL-SI" />
<Resource Language="SQ-AL" />
<Resource Language="SR-CYRL-BA" />
<Resource Language="SR-CYRL-RS" />
<Resource Language="SR-LATN-RS" />
<Resource Language="SV-SE" />
<Resource Language="TA-IN" />
<Resource Language="TE-IN" />
<Resource Language="TH-TH" />
<Resource Language="TR-TR" />
<Resource Language="TT-RU" />
<Resource Language="UG-CN" />
<Resource Language="UK-UA" />
<Resource Language="UR-PK" />
<Resource Language="UZ-LATN-UZ" />
<Resource Language="VI-VN" />
<Resource Language="ZH-CN" />
<Resource Language="ZH-TW" />
</Resources>
<Applications>
@@ -74,7 +162,7 @@
Enabled="false"
DisplayName="ms-resource:AppName" />
</uap5:Extension>
<!-- <uap3:Extension Category="windows.appExtension">
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.console.host"
Id="OpenConsole"
DisplayName="OpenConsole"
@@ -88,7 +176,7 @@
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.terminal.host"
Id="Terminal"
DisplayName="Windows Terminal"
DisplayName="Terminal"
Description="Terminal host built from microsoft/terminal open source repository"
PublicFolder="Public">
<uap3:Properties>
@@ -102,15 +190,15 @@
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
</com:ComInterface>
</com:Extension> -->
</com:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<!-- <com:ExeServer DisplayName="OpenConsole" Executable="OpenConsole.exe">
<com:ExeServer DisplayName="OpenConsole" Executable="OpenConsole.exe">
<com:Class Id="2EACA947-7F5F-4CFA-BA87-8F7FBEEFBE69"/>
</com:ExeServer>
<com:ExeServer DisplayName="WindowsTerminal" Executable="WindowsTerminal.exe">
<com:Class Id="E12CFF52-A866-4C77-9A90-F570A7AA2C6B"/>
</com:ExeServer> -->
</com:ExeServer>
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
<com:Class Id="9f156763-7844-4dc4-b2b1-901f640f5155" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
@@ -147,4 +235,9 @@
</uap7:SharedFonts>
</uap7:Extension>
</Extensions>
<mp:PhoneIdentity
PhoneProductId="3a855625-ba50-46d5-b806-cb4520089c64"
PhonePublisherId="95d94207-0c7c-47ed-82db-d75c81153c35" />
</Package>

View File

@@ -117,22 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AppName" xml:space="preserve">
<value>Windows Terminal</value>
</data>
<data name="AppNameDev" xml:space="preserve">
<value>Windows Terminal Dev</value>
</data>
<data name="AppNamePre" xml:space="preserve">
<value>Windows Terminal Preview</value>
</data>
<data name="AppShortName" xml:space="preserve">
<value>Terminal</value>
</data>
<data name="AppShortNameDev" xml:space="preserve">
<value>Terminal Dev</value>
</data>
<data name="AppShortNamePre" xml:space="preserve">
<value>Terminal Preview</value>
</data>
</root>
</root>

View File

@@ -117,13 +117,52 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AppName" xml:space="preserve">
<value>Terminal</value>
<comment>{Locked}</comment>
</data>
<data name="AppNameDev" xml:space="preserve">
<value>Terminal Dev</value>
<comment>{Locked}</comment>
</data>
<data name="AppNamePre" xml:space="preserve">
<value>Terminal Preview</value>
<comment>{Locked}</comment>
</data>
<data name="AppStoreName" xml:space="preserve">
<value>Windows Terminal</value>
<comment>{Locked}</comment>
</data>
<data name="AppStoreNameDev" xml:space="preserve">
<value>Windows Terminal Dev</value>
<comment>{Locked}</comment>
</data>
<data name="AppStoreNamePre" xml:space="preserve">
<value>Windows Terminal Preview</value>
<comment>{Locked}</comment>
</data>
<data name="AppShortName" xml:space="preserve">
<value>Terminal</value>
<comment>{Locked}</comment>
</data>
<data name="AppShortNameDev" xml:space="preserve">
<value>Terminal Dev</value>
<comment>{Locked}</comment>
</data>
<data name="AppShortNamePre" xml:space="preserve">
<value>Terminal Preview</value>
<comment>{Locked}</comment>
</data>
<data name="AppDescription" xml:space="preserve">
<value>The New Windows Terminal</value>
<comment>{Locked}</comment>
</data>
<data name="AppDescriptionDev" xml:space="preserve">
<value>The Windows Terminal, but Unofficial</value>
<comment>{Locked}</comment>
</data>
<data name="AppDescriptionPre" xml:space="preserve">
<value>Windows Terminal with a preview of upcoming features</value>
<comment>{Locked}</comment>
</data>
</root>
</root>

View File

@@ -5,9 +5,11 @@
#include "../TerminalSettingsModel/ColorScheme.h"
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../types/inc/colorTable.hpp"
#include "JsonTestClass.h"
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
@@ -32,339 +34,293 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(CanLayerColorScheme);
TEST_METHOD(LayerColorSchemeProperties);
TEST_METHOD(ParseSimpleColorScheme);
TEST_METHOD(LayerColorSchemesOnArray);
TEST_METHOD(UpdateSchemeReferences);
TEST_CLASS_SETUP(ClassSetup)
static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{
InitializeJsonReader();
return true;
return Core::Color{ r, g, b, 255 };
}
};
void ColorSchemeTests::CanLayerColorScheme()
void ColorSchemeTests::ParseSimpleColorScheme()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101"
})" };
const std::string scheme1String{ R"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505"
})" };
const std::string scheme3String{ R"({
// "name": "scheme3",
"foreground": "#060606",
"background": "#070707"
})" };
const std::string campbellScheme{ "{"
"\"background\" : \"#0C0C0C\","
"\"black\" : \"#0C0C0C\","
"\"blue\" : \"#0037DA\","
"\"brightBlack\" : \"#767676\","
"\"brightBlue\" : \"#3B78FF\","
"\"brightCyan\" : \"#61D6D6\","
"\"brightGreen\" : \"#16C60C\","
"\"brightPurple\" : \"#B4009E\","
"\"brightRed\" : \"#E74856\","
"\"brightWhite\" : \"#F2F2F2\","
"\"brightYellow\" : \"#F9F1A5\","
"\"cursorColor\" : \"#FFFFFF\","
"\"cyan\" : \"#3A96DD\","
"\"foreground\" : \"#F2F2F2\","
"\"green\" : \"#13A10E\","
"\"name\" : \"Campbell\","
"\"purple\" : \"#881798\","
"\"red\" : \"#C50F1F\","
"\"selectionBackground\" : \"#131313\","
"\"white\" : \"#CCCCCC\","
"\"yellow\" : \"#C19C00\""
"}" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
const auto schemeObject = VerifyParseSucceeded(campbellScheme);
auto scheme = ColorScheme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"Campbell", scheme->Name());
VERIFY_ARE_EQUAL(til::color(0xf2, 0xf2, 0xf2, 255), til::color{ scheme->Foreground() });
VERIFY_ARE_EQUAL(til::color(0x0c, 0x0c, 0x0c, 255), til::color{ scheme->Background() });
VERIFY_ARE_EQUAL(til::color(0x13, 0x13, 0x13, 255), til::color{ scheme->SelectionBackground() });
VERIFY_ARE_EQUAL(til::color(0xFF, 0xFF, 0xFF, 255), til::color{ scheme->CursorColor() });
const auto scheme0 = ColorScheme::FromJson(scheme0Json);
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
const auto campbellSpan = gsl::make_span(expectedCampbellTable);
Utils::InitializeCampbellColorTable(campbellSpan);
Utils::SetColorTableAlpha(campbellSpan, 0);
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme0Json));
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme1Json));
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme3Json));
for (size_t i = 0; i < expectedCampbellTable.size(); i++)
{
const auto& expected = expectedCampbellTable.at(i);
const til::color actual{ scheme->Table().at(static_cast<uint32_t>(i)) };
VERIFY_ARE_EQUAL(expected, actual);
}
const auto scheme1 = ColorScheme::FromJson(scheme1Json);
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme0Json));
VERIFY_IS_TRUE(scheme1->ShouldBeLayered(scheme1Json));
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme3Json));
const auto scheme3 = ColorScheme::FromJson(scheme3Json);
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme0Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme1Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme3Json));
}
void ColorSchemeTests::LayerColorSchemeProperties()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101",
"selectionBackground": "#010100",
"cursorColor": "#010001",
"red": "#010000",
"green": "#000100",
"blue": "#000001"
})" };
const std::string scheme1String{ R"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303",
"selectionBackground": "#020200",
"cursorColor": "#040004",
"red": "#020000",
"blue": "#000002"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505",
"selectionBackground": "#030300",
"cursorColor": "#060006",
"red": "#030000",
"green": "#000300"
})" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
auto scheme0 = ColorScheme::FromJson(scheme0Json);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_Name);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 1), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(NoThrowString().Format(
L"Layering scheme1 on top of scheme0"));
scheme0->LayerJson(scheme1Json);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(NoThrowString().Format(
L"Layering scheme2Json on top of (scheme0+scheme1)"));
scheme0->LayerJson(scheme2Json);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 3, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 3, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(L"Roundtrip Test for Color Scheme");
Json::Value outJson{ scheme->ToJson() };
VERIFY_ARE_EQUAL(schemeObject, outJson);
}
void ColorSchemeTests::LayerColorSchemesOnArray()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101"
static constexpr std::string_view inboxSettings{ R"({
"schemes": [
{
"background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
}
]
})" };
const std::string scheme1String{ R"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505"
})" };
const std::string scheme3String{ R"({
// by not providing a name, the scheme will have the name ""
"foreground": "#060606",
"background": "#070707"
static constexpr std::string_view userSettings{ R"({
"profiles": [
{
"name" : "profile0"
}
],
"schemes": [
{
"background": "#121314",
"black": "#121314",
"blue": "#121314",
"brightBlack": "#121314",
"brightBlue": "#121314",
"brightCyan": "#121314",
"brightGreen": "#121314",
"brightPurple": "#121314",
"brightRed": "#121314",
"brightWhite": "#121314",
"brightYellow": "#121314",
"cursorColor": "#121314",
"cyan": "#121314",
"foreground": "#121314",
"green": "#121314",
"name": "Campbell",
"purple": "#121314",
"red": "#121314",
"selectionBackground": "#121314",
"white": "#121314",
"yellow": "#121314"
},
{
"background": "#012456",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell Powershell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
}
]
})" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
const auto settings = winrt::make_self<CascadiaSettings>(userSettings, inboxSettings);
auto settings = winrt::make_self<CascadiaSettings>();
const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
VERIFY_ARE_EQUAL(2u, colorSchemes.Size());
VERIFY_ARE_EQUAL(0u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
const auto scheme0 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell"));
VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Foreground());
VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Background());
settings->_LayerOrCreateColorScheme(scheme0Json);
{
for (auto kv : settings->_globals->ColorSchemes())
{
Log::Comment(NoThrowString().Format(
L"kv:%s->%s", kv.Key().data(), kv.Value().Name().data()));
}
VERIFY_ARE_EQUAL(1u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
}
settings->_LayerOrCreateColorScheme(scheme1Json);
{
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme2Json);
{
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme3Json);
{
VERIFY_ARE_EQUAL(3u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L""));
auto scheme2Proj = settings->_globals->ColorSchemes().Lookup(L"");
auto scheme2 = winrt::get_self<ColorScheme>(scheme2Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
}
const auto scheme1 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell Powershell"));
VERIFY_ARE_EQUAL(rgb(0xCC, 0xCC, 0xCC), scheme1->Foreground());
VERIFY_ARE_EQUAL(rgb(0x01, 0x24, 0x56), scheme1->Background());
}
void ColorSchemeTests::UpdateSchemeReferences()
{
const std::string settingsString{ R"json({
"defaultProfile": "Inherited reference",
"profiles": {
"defaults": {
"colorScheme": "Scheme 1"
},
"list": [
{
"name": "Explicit scheme reference",
"colorScheme": "Scheme 1"
},
{
"name": "Explicit reference; hidden",
"colorScheme": "Scheme 1",
"hidden": true
},
{
"name": "Inherited reference"
},
{
"name": "Different reference",
"colorScheme": "Scheme 2"
}
]
},
"schemes": [
{ "name": "Scheme 1" },
{ "name": "Scheme 2" },
{ "name": "Scheme 1 (renamed)" }
]
})json" };
static constexpr std::string_view settingsString{ R"json({
"defaultProfile": "Inherited reference",
"profiles": {
"defaults": {
"colorScheme": "Campbell"
},
"list": [
{
"name": "Explicit scheme reference",
"colorScheme": "Campbell"
},
{
"name": "Explicit reference; hidden",
"colorScheme": "Campbell",
"hidden": true
},
{
"name": "Inherited reference"
},
{
"name": "Different reference",
"colorScheme": "One Half Dark"
}
]
},
"schemes": [
{
"background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
},
{
"background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell (renamed)",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
},
{
"background": "#282C34",
"black": "#282C34",
"blue": "#61AFEF",
"brightBlack": "#5A6374",
"brightBlue": "#61AFEF",
"brightCyan": "#56B6C2",
"brightGreen": "#98C379",
"brightPurple": "#C678DD",
"brightRed": "#E06C75",
"brightWhite": "#DCDFE4",
"brightYellow": "#E5C07B",
"cursorColor": "#FFFFFF",
"cyan": "#56B6C2",
"foreground": "#DCDFE4",
"green": "#98C379",
"name": "One Half Dark",
"purple": "#C678DD",
"red": "#E06C75",
"selectionBackground": "#FFFFFF",
"white": "#DCDFE4",
"yellow": "#E5C07B"
}
]
})json" };
auto settings{ winrt::make_self<CascadiaSettings>(false) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString) };
// update all references to "Scheme 1"
const auto newName{ L"Scheme 1 (renamed)" };
settings->UpdateColorSchemeReferences(L"Scheme 1", newName);
const auto newName{ L"Campbell (renamed)" };
settings->UpdateColorSchemeReferences(L"Campbell", newName);
// verify profile defaults
Log::Comment(L"Profile Defaults");
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName());
// verify all other profiles
const auto& profiles{ settings->AllProfiles() };
{
const auto& prof{ profiles.GetAt(0) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(1) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(2) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(3) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(L"Scheme 2", prof.DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
}

View File

@@ -43,12 +43,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestLayerOnAutogeneratedName);
TEST_METHOD(TestGenerateCommandline);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
};
void CommandTests::ManyCommandsSameAction()
@@ -152,6 +146,10 @@ namespace SettingsModelLocalTests
{ "name": "command4", "command": { "action": "splitPane" } },
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } },
{ "name": "command6", "command": { "action": "splitPane", "size": 0.25 } },
{ "name": "command7", "command": { "action": "splitPane", "split": "right" } },
{ "name": "command8", "command": { "action": "splitPane", "split": "left" } },
{ "name": "command9", "command": { "action": "splitPane", "split": "up" } },
{ "name": "command10", "command": { "action": "splitPane", "split": "down" } },
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
@@ -160,7 +158,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(5u, commands.Size());
VERIFY_ARE_EQUAL(9u, commands.Size());
{
auto command = commands.Lookup(L"command1");
@@ -170,7 +168,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
@@ -181,7 +179,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
@@ -192,7 +190,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
@@ -203,7 +201,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
@@ -214,9 +212,53 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.25, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command7");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command8");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Left, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command9");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Up, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command10");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
}
void CommandTests::TestSplitPaneBadSize()
@@ -244,7 +286,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.25, realArgs.SplitSize());
}
}
@@ -286,8 +328,10 @@ namespace SettingsModelLocalTests
const std::string commands0String{ R"([
{ "command": { "action": "splitPane", "split": null } },
{ "command": { "action": "splitPane", "split": "vertical" } },
{ "command": { "action": "splitPane", "split": "horizontal" } },
{ "command": { "action": "splitPane", "split": "left" } },
{ "command": { "action": "splitPane", "split": "right" } },
{ "command": { "action": "splitPane", "split": "up" } },
{ "command": { "action": "splitPane", "split": "down" } },
{ "command": { "action": "splitPane", "split": "none" } },
{ "command": { "action": "splitPane" } },
{ "command": { "action": "splitPane", "split": "auto" } },
@@ -301,10 +345,10 @@ namespace SettingsModelLocalTests
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
// There are only 3 commands here: all of the `"none"`, `"auto"`,
// There are only 5 commands here: all of the `"none"`, `"auto"`,
// `"foo"`, `null`, and <no args> bindings all generate the same action,
// which will generate just a single name for all of them.
VERIFY_ARE_EQUAL(3u, commands.Size());
VERIFY_ARE_EQUAL(5u, commands.Size());
{
auto command = commands.Lookup(L"Split pane");
@@ -314,27 +358,47 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
}
{
auto command = commands.Lookup(L"Split pane, split: vertical");
auto command = commands.Lookup(L"Split pane, split: left");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Left, realArgs.SplitDirection());
}
{
auto command = commands.Lookup(L"Split pane, split: horizontal");
auto command = commands.Lookup(L"Split pane, split: right");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
}
{
auto command = commands.Lookup(L"Split pane, split: up");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Up, realArgs.SplitDirection());
}
{
auto command = commands.Lookup(L"Split pane, split: down");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
}
}
void CommandTests::TestLayerOnAutogeneratedName()
@@ -360,7 +424,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = command.ActionAndArgs().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
}
}
@@ -401,6 +465,10 @@ namespace SettingsModelLocalTests
"name":"action7_startingDirectoryWithTrailingSlash",
"command": { "action": "newWindow", "startingDirectory":"C:\\", "commandline": "bar.exe" }
},
{
"name":"action8_tabTitleEscaping",
"command": { "action": "newWindow", "tabTitle":"\\\";foo\\" }
}
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
@@ -409,7 +477,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(8u, commands.Size());
VERIFY_ARE_EQUAL(9u, commands.Size());
{
auto command = commands.Lookup(L"action0");
@@ -522,5 +590,20 @@ namespace SettingsModelLocalTests
L"cmdline: \"%s\"", cmdline.c_str()));
VERIFY_ARE_EQUAL(L"--startingDirectory \"C:\\\\\" -- \"bar.exe\"", terminalArgs.ToCommandline());
}
{
auto command = commands.Lookup(L"action8_tabTitleEscaping");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::NewWindow, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<NewWindowArgs>();
VERIFY_IS_NOT_NULL(realArgs);
const auto& terminalArgs = realArgs.TerminalArgs();
VERIFY_IS_NOT_NULL(terminalArgs);
auto cmdline = terminalArgs.ToCommandline();
Log::Comment(NoThrowString().Format(
L"cmdline: \"%s\"", cmdline.c_str()));
VERIFY_ARE_EQUAL(LR"-(--title "\\\"\;foo\\")-", terminalArgs.ToCommandline());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,44 +7,34 @@ Module Name:
Abstract:
- This class is a helper that can be used to quickly create tests that need to
read & parse json data. Test classes that need to read JSON should make sure
to derive from this class, and also make sure to call InitializeJsonReader()
in the TEST_CLASS_SETUP().
read & parse json data.
Author(s):
Mike Griese (migrie) August-2019
--*/
#pragma once
class JsonTestClass
{
public:
void InitializeJsonReader()
static Json::Value VerifyParseSucceeded(const std::string_view& content)
{
_reader = std::unique_ptr<Json::CharReader>(Json::CharReaderBuilder::CharReaderBuilder().newCharReader());
};
static const std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
void InitializeJsonWriter()
{
_writer = std::unique_ptr<Json::StreamWriter>(Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter());
}
Json::Value VerifyParseSucceeded(std::string content)
{
Json::Value root;
std::string errs;
const bool parseResult = _reader->parse(content.c_str(), content.c_str() + content.size(), &root, &errs);
const bool parseResult = reader->parse(content.data(), content.data() + content.size(), &root, &errs);
VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str());
return root;
};
std::string toString(const Json::Value& json)
static std::string toString(const Json::Value& json)
{
static const std::unique_ptr<Json::StreamWriter> writer{ Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter() };
std::stringstream s;
_writer->write(json, &s);
writer->write(json, &s);
return s.str();
}
protected:
std::unique_ptr<Json::CharReader> _reader;
std::unique_ptr<Json::StreamWriter> _writer;
};

View File

@@ -59,12 +59,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestGetKeyBindingForAction);
TEST_METHOD(KeybindingsWithoutVkey);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
};
void KeyBindingsTests::KeyChords()
@@ -432,7 +426,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().as<SplitPaneArgs>();
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
}
{
KeyChord kc{ true, false, false, false, static_cast<int32_t>('E'), 0 };
@@ -440,7 +434,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().as<SplitPaneArgs>();
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
}
{
KeyChord kc{ true, false, false, false, static_cast<int32_t>('G'), 0 };
@@ -448,7 +442,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().as<SplitPaneArgs>();
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
}
{
KeyChord kc{ true, false, false, false, static_cast<int32_t>('H'), 0 };
@@ -456,7 +450,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().as<SplitPaneArgs>();
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
}
}

View File

@@ -7,6 +7,8 @@
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h"
#include <defaults.h>
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging;
@@ -32,81 +34,88 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(CanLayerProfile);
TEST_METHOD(ProfileGeneratesGuid);
TEST_METHOD(LayerProfileProperties);
TEST_METHOD(LayerProfileIcon);
TEST_METHOD(LayerProfilesOnArray);
TEST_METHOD(DuplicateProfileTest);
TEST_METHOD(TestGenGuidsForProfiles);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
TEST_METHOD(TestCorrectOldDefaultShellPaths);
};
void ProfileTests::CanLayerProfile()
void ProfileTests::ProfileGeneratesGuid()
{
const std::string profile0String{ R"({
"name" : "profile0",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile1String{ R"({
"name" : "profile1",
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile2String{ R"({
"name" : "profile2",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile3String{ R"({
"name" : "profile3"
})" };
// Parse some profiles without guids. We should NOT generate new guids
// for them. If a profile doesn't have a GUID, we'll leave its _guid
// set to nullopt. The Profile::Guid() getter will
// ensure all profiles have a GUID that's actually set.
// The null guid _is_ a valid guid, so we won't re-generate that
// guid. null is _not_ a valid guid, so we'll leave that nullopt
const auto profile0Json = VerifyParseSucceeded(profile0String);
const auto profile1Json = VerifyParseSucceeded(profile1String);
const auto profile2Json = VerifyParseSucceeded(profile2String);
const auto profile3Json = VerifyParseSucceeded(profile3String);
// See SettingsTests::ValidateProfilesGenerateGuids for a version of
// this test that includes synthesizing GUIDS for profiles without GUIDs
// set
const std::string profileWithoutGuid{ R"({
"name" : "profile0"
})" };
const std::string secondProfileWithoutGuid{ R"({
"name" : "profile1"
})" };
const std::string profileWithNullForGuid{ R"({
"name" : "profile2",
"guid" : null
})" };
const std::string profileWithNullGuid{ R"({
"name" : "profile3",
"guid" : "{00000000-0000-0000-0000-000000000000}"
})" };
const std::string profileWithGuid{ R"({
"name" : "profile4",
"guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
})" };
const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid);
const auto profile1Json = VerifyParseSucceeded(secondProfileWithoutGuid);
const auto profile2Json = VerifyParseSucceeded(profileWithNullForGuid);
const auto profile3Json = VerifyParseSucceeded(profileWithNullGuid);
const auto profile4Json = VerifyParseSucceeded(profileWithGuid);
const auto profile0 = implementation::Profile::FromJson(profile0Json);
VERIFY_IS_FALSE(profile0->ShouldBeLayered(profile1Json));
VERIFY_IS_TRUE(profile0->ShouldBeLayered(profile2Json));
VERIFY_IS_FALSE(profile0->ShouldBeLayered(profile3Json));
const auto profile1 = implementation::Profile::FromJson(profile1Json);
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile0Json));
// A profile _can_ be layered with itself, though what's the point?
VERIFY_IS_TRUE(profile1->ShouldBeLayered(profile1Json));
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile2Json));
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile3Json));
const auto profile2 = implementation::Profile::FromJson(profile2Json);
const auto profile3 = implementation::Profile::FromJson(profile3Json);
const auto profile4 = implementation::Profile::FromJson(profile4Json);
const winrt::guid cmdGuid = Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}");
const winrt::guid nullGuid{};
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile0Json));
// A profile _can_ be layered with itself, though what's the point?
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json));
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json));
VERIFY_IS_TRUE(profile3->ShouldBeLayered(profile3Json));
VERIFY_IS_FALSE(profile0->HasGuid());
VERIFY_IS_FALSE(profile1->HasGuid());
VERIFY_IS_FALSE(profile2->HasGuid());
VERIFY_IS_TRUE(profile3->HasGuid());
VERIFY_IS_TRUE(profile4->HasGuid());
VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid);
VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid);
}
void ProfileTests::LayerProfileProperties()
{
const std::string profile0String{ R"({
static constexpr std::string_view profile0String{ R"({
"name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#000000",
"background": "#010101",
"selectionBackground": "#010101"
})" };
const std::string profile1String{ R"({
static constexpr std::string_view profile1String{ R"({
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#020202",
"startingDirectory": "C:/"
})" };
const std::string profile2String{ R"({
static constexpr std::string_view profile2String{ R"({
"name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#030303",
@@ -172,21 +181,21 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfileIcon()
{
const std::string profile0String{ R"({
static constexpr std::string_view profile0String{ R"({
"name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "not-null.png"
})" };
const std::string profile1String{ R"({
static constexpr std::string_view profile1String{ R"({
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": null
})" };
const std::string profile2String{ R"({
static constexpr std::string_view profile2String{ R"({
"name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile3String{ R"({
static constexpr std::string_view profile3String{ R"({
"name": "profile3",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "another-real.png"
@@ -228,102 +237,171 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfilesOnArray()
{
const std::string profile0String{ R"({
"name" : "profile0",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
static constexpr std::string_view inboxProfiles{ R"({
"profiles": [
{
"name" : "profile0",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile1",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile2",
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
}
]
})" };
const std::string profile1String{ R"({
"name" : "profile1",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile2String{ R"({
"name" : "profile2",
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile3String{ R"({
"name" : "profile3",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile4String{ R"({
"name" : "profile4",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
static constexpr std::string_view userProfiles{ R"({
"profiles": [
{
"name" : "profile3",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile4",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
}
]
})" };
const auto profile0Json = VerifyParseSucceeded(profile0String);
const auto profile1Json = VerifyParseSucceeded(profile1String);
const auto profile2Json = VerifyParseSucceeded(profile2String);
const auto profile3Json = VerifyParseSucceeded(profile3String);
const auto profile4Json = VerifyParseSucceeded(profile4String);
auto settings = winrt::make_self<implementation::CascadiaSettings>();
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size());
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile0Json);
VERIFY_ARE_EQUAL(1u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile1Json);
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile2Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
settings->_LayerOrCreateProfile(profile3Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile3", settings->_allProfiles.GetAt(0).Name());
settings->_LayerOrCreateProfile(profile4Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile4", settings->_allProfiles.GetAt(0).Name());
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles, inboxProfiles);
const auto allProfiles = settings->AllProfiles();
VERIFY_ARE_EQUAL(3u, allProfiles.Size());
VERIFY_ARE_EQUAL(L"profile3", allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile4", allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile2", allProfiles.GetAt(2).Name());
}
void ProfileTests::DuplicateProfileTest()
{
const std::string profile0String{ R"({
"name" : "profile0",
"backgroundImage" : "some//path"
static constexpr std::string_view userProfiles{ R"({
"profiles": {
"defaults": {
"font": {
"size": 123
}
},
"list": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"backgroundImage": "file:///some/path",
"hidden": false,
}
]
}
})" };
const auto profile0Json = VerifyParseSucceeded(profile0String);
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles);
const auto profile = settings->AllProfiles().GetAt(0);
const auto duplicatedProfile = settings->DuplicateProfile(profile);
auto settings = winrt::make_self<implementation::CascadiaSettings>();
// GH#11392: Ensure duplicated profiles properly inherit the base layer, even for nested objects.
VERIFY_ARE_EQUAL(123, duplicatedProfile.FontInfo().FontSize());
settings->_LayerOrCreateProfile(profile0Json);
auto duplicatedProfile = settings->DuplicateProfile(*settings->_FindMatchingProfile(profile0Json));
duplicatedProfile.Name(L"profile0");
duplicatedProfile.Guid(profile.Guid());
duplicatedProfile.Name(profile.Name());
const auto json = winrt::get_self<implementation::Profile>(profile)->ToJson();
const auto duplicatedJson = winrt::get_self<implementation::Profile>(duplicatedProfile)->ToJson();
VERIFY_ARE_EQUAL(profile0Json, duplicatedJson);
VERIFY_ARE_EQUAL(json, duplicatedJson, til::u8u16(toString(duplicatedJson)).c_str());
}
void ProfileTests::TestGenGuidsForProfiles()
{
// We'll generate GUIDs in the Profile::Guid getter. We should make sure that
// the GUID generated for a dynamic profile (with a source) is different
// than that of a profile without a source.
static constexpr std::string_view inboxSettings{ R"({
"profiles": [
{
"name" : "profile0",
"source": "Terminal.App.UnitTest.0"
},
{
"name" : "profile1"
}
]
})" };
static constexpr std::string_view userSettings{ R"({
"profiles": [
{
"name": "profile0",
"source": "Terminal.App.UnitTest.0",
},
{
"name": "profile0"
}
]
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userSettings, inboxSettings);
VERIFY_ARE_EQUAL(3u, settings->AllProfiles().Size());
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(0).Name());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(0).HasGuid());
VERIFY_IS_FALSE(settings->AllProfiles().GetAt(0).Source().empty());
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(1).Name());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(1).HasGuid());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(1).Source().empty());
VERIFY_ARE_NOT_EQUAL(settings->AllProfiles().GetAt(0).Guid(), settings->AllProfiles().GetAt(1).Guid());
}
void ProfileTests::TestCorrectOldDefaultShellPaths()
{
static constexpr std::string_view inboxProfiles{ R"({
"profiles": [
{
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
},
{
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "Command Prompt",
"commandline": "%SystemRoot%\\System32\\cmd.exe",
}
]
})" };
static constexpr std::string_view userProfiles{ R"({
"profiles": [
{
"name" : "powershell 1",
"commandline": "powershell.exe",
"guid" : "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}"
},
{
"name" : "powershell 2",
"commandline": "powershell.exe",
"guid" : "{61c54bbd-0000-5271-96e7-009a87ff44bf}"
},
{
"name" : "cmd 1",
"commandline": "cmd.exe",
"guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}"
},
{
"name" : "cmd 2",
"commandline": "cmd.exe",
"guid" : "{0caa0dad-0000-5f56-a8ff-afceeeaa6101}"
}
]
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles, inboxProfiles);
const auto allProfiles = settings->AllProfiles();
VERIFY_ARE_EQUAL(4u, allProfiles.Size());
VERIFY_ARE_EQUAL(L"powershell 1", allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"powershell 2", allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"cmd 1", allProfiles.GetAt(2).Name());
VERIFY_ARE_EQUAL(L"cmd 2", allProfiles.GetAt(3).Name());
VERIFY_ARE_EQUAL(L"%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", allProfiles.GetAt(0).Commandline());
VERIFY_ARE_EQUAL(L"powershell.exe", allProfiles.GetAt(1).Commandline());
VERIFY_ARE_EQUAL(L"%SystemRoot%\\System32\\cmd.exe", allProfiles.GetAt(2).Commandline());
VERIFY_ARE_EQUAL(L"cmd.exe", allProfiles.GetAt(3).Commandline());
}
}

View File

@@ -8,7 +8,6 @@
#include "JsonTestClass.h"
#include "TestUtils.h"
#include <defaults.h>
#include "../ut_app/TestDynamicProfileGenerator.h"
using namespace Microsoft::Console;
using namespace WEX::Logging;
@@ -43,13 +42,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(CascadiaSettings);
TEST_METHOD(LegacyFontSettings);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
InitializeJsonWriter();
return true;
}
private:
// Method Description:
// - deserializes and reserializes a json string representing a settings object model of type T
@@ -61,7 +53,7 @@ namespace SettingsModelLocalTests
// Return Value:
// - the JsonObject representing this instance
template<typename T>
void RoundtripTest(const std::string& jsonString)
void RoundtripTest(const std::string_view& jsonString)
{
const auto json{ VerifyParseSucceeded(jsonString) };
const auto settings{ T::FromJson(json) };
@@ -77,7 +69,7 @@ namespace SettingsModelLocalTests
void SerializationTests::GlobalSettings()
{
const std::string globalsString{ R"(
static constexpr std::string_view globalsString{ R"(
{
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
@@ -113,7 +105,7 @@ namespace SettingsModelLocalTests
"actions": []
})" };
const std::string smallGlobalsString{ R"(
static constexpr std::string_view smallGlobalsString{ R"(
{
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"actions": []
@@ -125,7 +117,7 @@ namespace SettingsModelLocalTests
void SerializationTests::Profile()
{
const std::string profileString{ R"(
static constexpr std::string_view profileString{ R"(
{
"name": "Windows PowerShell",
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
@@ -160,7 +152,7 @@ namespace SettingsModelLocalTests
"selectionBackground": "#CCAABB",
"useAcrylic": false,
"acrylicOpacity": 0.5,
"opacity": 50,
"backgroundImage": "made_you_look.jpeg",
"backgroundImageStretchMode": "uniformToFill",
@@ -175,7 +167,7 @@ namespace SettingsModelLocalTests
"experimental.retroTerminalEffect": false
})" };
const std::string smallProfileString{ R"(
static constexpr std::string_view smallProfileString{ R"(
{
"name": "Custom Profile"
})" };
@@ -183,7 +175,7 @@ namespace SettingsModelLocalTests
// Setting "tabColor" to null tests two things:
// - null should count as an explicit user-set value, not falling back to the parent's value
// - null should be acceptable even though we're working with colors
const std::string weirdProfileString{ R"(
static constexpr std::string_view weirdProfileString{ R"(
{
"guid" : "{8b039d4d-77ca-5a83-88e1-dfc8e895a127}",
"name": "Weird Profile",
@@ -200,7 +192,7 @@ namespace SettingsModelLocalTests
void SerializationTests::ColorScheme()
{
const std::string schemeString{ R"({
static constexpr std::string_view schemeString{ R"({
"name": "Campbell",
"cursorColor": "#FFFFFF",
@@ -233,52 +225,56 @@ namespace SettingsModelLocalTests
void SerializationTests::Actions()
{
// simple command
const std::string actionsString1{ R"([
static constexpr std::string_view actionsString1{ R"([
{ "command": "paste" }
])" };
// complex command
const std::string actionsString2A{ R"([
static constexpr std::string_view actionsString2A{ R"([
{ "command": { "action": "setTabColor" } }
])" };
const std::string actionsString2B{ R"([
static constexpr std::string_view actionsString2B{ R"([
{ "command": { "action": "setTabColor", "color": "#112233" } }
])" };
const std::string actionsString2C{ R"([
static constexpr std::string_view actionsString2C{ R"([
{ "command": { "action": "copy" } },
{ "command": { "action": "copy", "singleLine": true, "copyFormatting": "html" } }
])" };
// simple command with key chords
const std::string actionsString3{ R"([
static constexpr std::string_view actionsString3{ R"([
{ "command": "toggleAlwaysOnTop", "keys": "ctrl+a" },
{ "command": "toggleAlwaysOnTop", "keys": "ctrl+b" }
])" };
// complex command with key chords
const std::string actionsString4{ R"([
static constexpr std::string_view actionsString4A{ R"([
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+c" },
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" }
])" };
static constexpr std::string_view actionsString4B{ R"([
{ "command": { "action": "findMatch", "direction": "next" }, "keys": "ctrl+shift+s" },
{ "command": { "action": "findMatch", "direction": "prev" }, "keys": "ctrl+shift+r" }
])" };
// command with name and icon and multiple key chords
const std::string actionsString5{ R"([
static constexpr std::string_view actionsString5{ R"([
{ "icon": "image.png", "name": "Scroll To Top Name", "command": "scrollToTop", "keys": "ctrl+e" },
{ "command": "scrollToTop", "keys": "ctrl+f" }
])" };
// complex command with new terminal args
const std::string actionsString6{ R"([
static constexpr std::string_view actionsString6{ R"([
{ "command": { "action": "newTab", "index": 0 }, "keys": "ctrl+g" },
])" };
// complex command with meaningful null arg
const std::string actionsString7{ R"([
static constexpr std::string_view actionsString7{ R"([
{ "command": { "action": "renameWindow", "name": null }, "keys": "ctrl+h" }
])" };
// nested command
const std::string actionsString8{ R"([
static constexpr std::string_view actionsString8{ R"([
{
"name": "Change font size...",
"commands": [
@@ -290,7 +286,7 @@ namespace SettingsModelLocalTests
])" };
// iterable command
const std::string actionsString9A{ R"([
static constexpr std::string_view actionsString9A{ R"([
{
"name": "New tab",
"commands": [
@@ -303,12 +299,12 @@ namespace SettingsModelLocalTests
]
}
])" };
const std::string actionsString9B{ R"([
static constexpr std::string_view actionsString9B{ R"([
{
"commands":
"commands":
[
{
"command":
"command":
{
"action": "sendInput",
"input": "${profile.name}"
@@ -319,15 +315,15 @@ namespace SettingsModelLocalTests
"name": "Send Input ..."
}
])" };
const std::string actionsString9C{ R""([
static constexpr std::string_view actionsString9C{ R""([
{
"commands":
"commands":
[
{
"commands":
"commands":
[
{
"command":
"command":
{
"action": "sendInput",
"input": "${profile.name} ${scheme.name}"
@@ -342,9 +338,9 @@ namespace SettingsModelLocalTests
"name": "Send Input (Evil) ..."
}
])"" };
const std::string actionsString9D{ R""([
static constexpr std::string_view actionsString9D{ R""([
{
"command":
"command":
{
"action": "newTab",
"profile": "${profile.name}"
@@ -356,7 +352,7 @@ namespace SettingsModelLocalTests
])"" };
// unbound command
const std::string actionsString10{ R"([
static constexpr std::string_view actionsString10{ R"([
{ "command": "unbound", "keys": "ctrl+c" }
])" };
@@ -372,7 +368,8 @@ namespace SettingsModelLocalTests
RoundtripTest<implementation::ActionMap>(actionsString3);
Log::Comment(L"complex commands with key chords");
RoundtripTest<implementation::ActionMap>(actionsString4);
RoundtripTest<implementation::ActionMap>(actionsString4A);
RoundtripTest<implementation::ActionMap>(actionsString4B);
Log::Comment(L"command with name and icon and multiple key chords");
RoundtripTest<implementation::ActionMap>(actionsString5);
@@ -398,81 +395,77 @@ namespace SettingsModelLocalTests
void SerializationTests::CascadiaSettings()
{
const std::string settingsString{ R"({
"$schema": "https://aka.ms/terminal-profiles-schema",
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
static constexpr std::string_view settingsString{ R"({
"$help" : "https://aka.ms/terminal-documentation",
"$schema" : "https://aka.ms/terminal-profiles-schema",
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
"profiles": {
"defaults": {
"font": {
"face": "Zamora Code"
}
},
"list": [
{
"font": { "face": "Cascadia Code" },
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"name": "HowettShell"
},
{
"hidden": true,
"guid": "{c08b0496-e71c-5503-b84e-3af7a7a6d2a7}",
"name": "BhojwaniShell"
},
{
"antialiasingMode": "aliased",
"guid": "{fe9df758-ac22-5c20-922d-c7766cdd13af}",
"name": "NiksaShell"
}
]
},
"schemes": [
{
"name": "Cinnamon Roll",
"profiles": {
"defaults": {
"font": {
"face": "Zamora Code"
}
},
"list": [
{
"font": { "face": "Cascadia Code" },
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"name": "HowettShell"
},
{
"hidden": true,
"name": "BhojwaniShell"
},
{
"antialiasingMode": "aliased",
"name": "NiksaShell"
}
]
},
"schemes": [
{
"name": "Cinnamon Roll",
"cursorColor": "#FFFFFD",
"selectionBackground": "#FFFFFF",
"cursorColor": "#FFFFFD",
"selectionBackground": "#FFFFFF",
"background": "#3C0315",
"foreground": "#FFFFFD",
"background": "#3C0315",
"foreground": "#FFFFFD",
"black": "#282A2E",
"blue": "#0170C5",
"cyan": "#3F8D83",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48",
"brightBlack": "#676E7A",
"brightBlue": "#5C98C5",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76"
}
],
"actions": [
{ "command": { "action": "sendInput", "input": "VT Griese Mode" }, "keys": "ctrl+k" }
]
})" };
"black": "#282A2E",
"blue": "#0170C5",
"cyan": "#3F8D83",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48",
"brightBlack": "#676E7A",
"brightBlue": "#5C98C5",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76"
}
],
"actions": [
{ "command": { "action": "renameTab", "title": "Liang Tab" }, "keys": "ctrl+t" },
{ "command": { "action": "sendInput", "input": "VT Griese Mode" }, "keys": "ctrl+k" },
{ "command": { "action": "renameWindow", "name": "Hecker Window" }, "keys": "ctrl+l" }
]
})" };
auto settings{ winrt::make_self<implementation::CascadiaSettings>(false) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
const auto settings{ winrt::make_self<implementation::CascadiaSettings>(settingsString) };
const auto result{ settings->ToJson() };
VERIFY_ARE_EQUAL(toString(settings->_userSettings), toString(result));
VERIFY_ARE_EQUAL(toString(VerifyParseSucceeded(settingsString)), toString(result));
}
void SerializationTests::LegacyFontSettings()
{
const std::string profileString{ R"(
static constexpr std::string_view profileString{ R"(
{
"name": "Profile with legacy font settings",
@@ -481,7 +474,7 @@ namespace SettingsModelLocalTests
"fontWeight": "normal"
})" };
const std::string expectedOutput{ R"(
static constexpr std::string_view expectedOutput{ R"(
{
"name": "Profile with legacy font settings",

View File

@@ -80,8 +80,8 @@
If you don't have this, then you'll see an error like
"(init.obj) : error LNK2005: DllMain already defined in MSVCRTD.lib(dll_dllmain_stub.obj)"
-->
<AdditionalOptions Condition="'$(Platform)'=='Win32'">/INCLUDE:_DllMain@12</AdditionalOptions>
<AdditionalOptions Condition="'$(Platform)'!='Win32'">/INCLUDE:DllMain</AdditionalOptions>
<AdditionalOptions Condition="'$(Platform)'=='Win32'">%(AdditionalOptions) /INCLUDE:_DllMain@12</AdditionalOptions>
<AdditionalOptions Condition="'$(Platform)'!='Win32'">%(AdditionalOptions) /INCLUDE:DllMain</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -98,10 +98,10 @@
<!-- From Microsoft.UI.Xaml.targets -->
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
<_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot>
<_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot>
</PropertyGroup>
<!-- We actually can just straight up reference MUX here, it's fine -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
</Project>

View File

@@ -3,6 +3,8 @@
#include "pch.h"
#include <til/rand.h>
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../TerminalSettingsModel/TerminalSettings.h"
#include "TestUtils.h"
@@ -34,14 +36,13 @@ namespace SettingsModelLocalTests
END_TEST_CLASS()
TEST_METHOD(TryCreateWinRTType);
TEST_METHOD(TestTerminalArgsForBinding);
TEST_METHOD(CommandLineToArgvW);
TEST_METHOD(NormalizeCommandLine);
TEST_METHOD(GetProfileForArgsWithCommandline);
TEST_METHOD(MakeSettingsForProfile);
TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist);
TEST_METHOD(TestLayerProfileOnColorScheme);
TEST_METHOD(TestCommandlineToTitlePromotion);
TEST_CLASS_SETUP(ClassSetup)
@@ -60,9 +61,212 @@ namespace SettingsModelLocalTests
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
}
// CascadiaSettings::_normalizeCommandLine abuses some aspects from CommandLineToArgvW
// to simplify the implementation. It assumes that all arguments returned by
// CommandLineToArgvW are returned back to back in memory as "arg1\0arg2\0arg3\0...".
// This test ensures CommandLineToArgvW doesn't change just to be sure.
void TerminalSettingsTests::CommandLineToArgvW()
{
pcg_engines::oneseq_dxsm_64_32 rng{ til::gen_random<uint64_t>() };
const auto expectedArgc = static_cast<int>(rng(16) + 1);
std::wstring expectedArgv;
std::wstring input;
// We generate up to 16 arguments. Each argument is up to 64 chars long, is quoted
// (2 chars, only applies to the input) and separated by a whitespace (1 char).
expectedArgv.reserve(expectedArgc * 65);
input.reserve(expectedArgc * 67);
for (int i = 0; i < expectedArgc; ++i)
{
const bool useQuotes = static_cast<bool>(rng(2));
// We need to ensure there is at least one character
const auto count = static_cast<size_t>(rng(64) + 1);
const auto ch = static_cast<wchar_t>(rng('z' - 'a' + 1) + 'a');
if (i != 0)
{
expectedArgv.push_back(L'\0');
input.push_back(L' ');
}
if (useQuotes)
{
input.push_back(L'"');
}
expectedArgv.append(count, ch);
input.append(count, ch);
if (useQuotes)
{
input.push_back(L'"');
}
}
Log::Comment(NoThrowString().Format(input.c_str()));
int argc;
wil::unique_hlocal_ptr<PWSTR[]> argv{ ::CommandLineToArgvW(input.c_str(), &argc) };
VERIFY_ARE_EQUAL(expectedArgc, argc);
VERIFY_IS_NOT_NULL(argv);
const auto lastArg = argv[argc - 1];
const auto beg = argv[0];
const auto end = lastArg + wcslen(lastArg);
VERIFY_IS_GREATER_THAN(end, beg);
VERIFY_ARE_EQUAL(expectedArgv.size(), static_cast<size_t>(end - beg));
VERIFY_ARE_EQUAL(0, memcmp(beg, expectedArgv.data(), expectedArgv.size()));
}
// This unit test covers GH#12345.
// * paths with more than 1 whitespace
// * paths sharing a common prefix with another directory
void TerminalSettingsTests::NormalizeCommandLine()
{
using namespace std::string_literals;
static constexpr auto touch = [](const auto& path) {
std::ofstream file{ path };
};
std::wstring guid;
{
GUID g{};
THROW_IF_FAILED(CoCreateGuid(&g));
guid = fmt::format(
L"{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
g.Data1,
g.Data2,
g.Data3,
g.Data4[0],
g.Data4[1],
g.Data4[2],
g.Data4[3],
g.Data4[4],
g.Data4[5],
g.Data4[6],
g.Data4[7]);
}
const auto tmpdir = std::filesystem::temp_directory_path();
const auto dir1 = tmpdir / guid;
const auto dir2 = tmpdir / (guid + L" two");
const auto file1 = dir1 / L"file 1.exe";
const auto file2 = dir2 / L"file 2.exe";
const auto cleanup = wil::scope_exit([&]() {
std::error_code ec;
remove_all(dir1, ec);
remove_all(dir2, ec);
});
create_directory(dir1);
create_directory(dir2);
touch(file1);
touch(file2);
{
const auto commandLine = file2.native() + LR"( -foo "bar1 bar2" -baz)"s;
const auto expected = file2.native() + L"\0-foo\0bar1 bar2\0-baz"s;
const auto actual = implementation::CascadiaSettings::NormalizeCommandLine(commandLine.c_str());
VERIFY_ARE_EQUAL(expected, actual);
}
{
const auto commandLine = L"C:\\";
const auto expected = L"C:\\";
const auto actual = implementation::CascadiaSettings::NormalizeCommandLine(commandLine);
VERIFY_ARE_EQUAL(expected, actual);
}
}
void TerminalSettingsTests::GetProfileForArgsWithCommandline()
{
// I'm exclusively using cmd.exe as I know exactly where it resides at.
static constexpr std::string_view settingsJson{ R"({
"profiles": {
"defaults": {
"historySize": 123
},
"list": [
{
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"commandline": "%SystemRoot%\\System32\\cmd.exe"
},
{
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A"
},
{
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A /B"
},
{
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A /C",
"connectionType": "{9a9977a7-1fe0-49c0-b6c0-13a0cd1c98a1}"
},
{
"guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}",
"commandline": "C:\\invalid.exe",
}
]
}
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
struct TestCase
{
std::wstring_view input;
int expected;
};
static constexpr std::array testCases{
// Base test.
TestCase{ L"cmd.exe", 0 },
// SearchPathW() normalization + case insensitive matching.
TestCase{ L"cmd.exe /a", 1 },
TestCase{ L"%SystemRoot%\\System32\\cmd.exe /A", 1 },
// Test that we don't pick the equally long but different "/A /B" variant.
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
// Test that we don't pick the shorter "/A" variant,
// but do pick the shorter "/A /B" variant for longer inputs.
TestCase{ L"cmd.exe /A /B", 2 },
TestCase{ L"cmd.exe /A /B /C", 2 },
// Ignore profiles with a connection type, like the Azure cloud shell.
// Instead it should pick any other prefix.
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
// Failure to normalize a path (e.g. because the path doesn't exist)
// should yield the unmodified input string (see NormalizeCommandLine).
TestCase{ L"C:\\invalid.exe /A /B", 4 },
// Return base layer profile for missing profiles.
TestCase{ L"C:\\Windows\\regedit.exe", -1 },
};
for (const auto& testCase : testCases)
{
NewTerminalArgs args;
args.Commandline(testCase.input);
const auto profile = settings->GetProfileForArgs(args);
VERIFY_IS_NOT_NULL(profile);
if (testCase.expected < 0)
{
VERIFY_ARE_EQUAL(123, profile.HistorySize());
}
else
{
GUID expectedGUID{ 0x6239a42c, static_cast<uint16_t>(0x1111 * testCase.expected), 0x49a3, { 0x80, 0xbd, 0xe8, 0xfd, 0xd0, 0x45, 0x18, 0x5c } };
VERIFY_ARE_EQUAL(expectedGUID, static_cast<const GUID&>(profile.Guid()));
}
}
}
void TerminalSettingsTests::TestTerminalArgsForBinding()
{
const std::string settingsJson{ R"(
static constexpr std::string_view settingsJson{ R"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [
@@ -106,12 +310,12 @@ namespace SettingsModelLocalTests
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
CascadiaSettings settings{ til::u8u16(settingsJson) };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
auto actionMap = settings.GlobalSettings().ActionMap();
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto actionMap = settings->GlobalSettings().ActionMap();
VERIFY_ARE_EQUAL(3u, settings->ActiveProfiles().Size());
const auto profile2Guid = settings.ActiveProfiles().GetAt(2).Guid();
const auto profile2Guid = settings->ActiveProfiles().GetAt(2).Guid();
VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid);
const auto& actionMapImpl{ winrt::get_self<implementation::ActionMap>(actionMap) };
@@ -124,15 +328,15 @@ namespace SettingsModelLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@@ -145,7 +349,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -153,8 +357,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@@ -167,7 +371,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -175,8 +379,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@@ -189,7 +393,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -197,8 +401,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@@ -211,7 +415,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -219,13 +423,13 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled())
{
// This action specified a command but no profile; it gets reassigned to the base profile
VERIFY_ARE_EQUAL(settings.ProfileDefaults(), profile);
VERIFY_ARE_EQUAL(settings->ProfileDefaults(), profile);
VERIFY_ARE_EQUAL(29, termSettings.HistorySize());
}
else
@@ -242,7 +446,7 @@ namespace SettingsModelLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -251,8 +455,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@@ -271,8 +475,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@@ -292,8 +496,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@@ -315,8 +519,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@@ -337,8 +541,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@@ -360,8 +564,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@@ -385,8 +589,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@@ -399,7 +603,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::MakeSettingsForProfile()
{
// Test that making settings generally works.
const std::string settingsString{ R"(
static constexpr std::string_view settingsString{ R"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -415,17 +619,17 @@ namespace SettingsModelLocalTests
}
]
})" };
CascadiaSettings settings{ til::u8u16(settingsString) };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsString);
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const auto profile1 = settings.FindProfile(guid1);
const auto profile2 = settings.FindProfile(guid2);
const auto profile1 = settings->FindProfile(guid1);
const auto profile2 = settings->FindProfile(guid2);
try
{
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile1, nullptr) };
auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile1, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize());
}
@@ -436,7 +640,7 @@ namespace SettingsModelLocalTests
try
{
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile2, nullptr) };
auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile2, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize());
}
@@ -447,7 +651,7 @@ namespace SettingsModelLocalTests
try
{
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) };
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(*settings, nullptr, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, termSettings);
VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize());
}
@@ -463,7 +667,7 @@ namespace SettingsModelLocalTests
// defaultProfile that's not in the list, we validate the settings, and
// then call MakeSettings(nullopt). The validation should ensure that
// the default profile is something reasonable
const std::string settingsString{ R"(
static constexpr std::string_view settingsString{ R"(
{
"defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -479,14 +683,14 @@ namespace SettingsModelLocalTests
}
]
})" };
CascadiaSettings settings{ til::u8u16(settingsString) };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsString);
VERIFY_ARE_EQUAL(2u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(2u, settings.ActiveProfiles().Size());
VERIFY_ARE_EQUAL(settings.GlobalSettings().DefaultProfile(), settings.ActiveProfiles().GetAt(0).Guid());
VERIFY_ARE_EQUAL(2u, settings->Warnings().Size());
VERIFY_ARE_EQUAL(2u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(settings->GlobalSettings().DefaultProfile(), settings->ActiveProfiles().GetAt(0).Guid());
try
{
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) };
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(*settings, nullptr, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, termSettings);
VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize());
}
@@ -501,7 +705,7 @@ namespace SettingsModelLocalTests
Log::Comment(NoThrowString().Format(
L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly."));
const std::string settings0String{ R"(
static constexpr std::string_view settings0String{ R"(
{
"defaultProfile": "profile5",
"profiles": [
@@ -534,18 +738,50 @@ namespace SettingsModelLocalTests
"schemes": [
{
"name": "schemeWithCursorColor",
"cursorColor": "#123456"
"cursorColor": "#123456",
"black": "#121314",
"red": "#121314",
"green": "#121314",
"yellow": "#121314",
"blue": "#121314",
"purple": "#121314",
"cyan": "#121314",
"white": "#121314",
"brightBlack": "#121314",
"brightRed": "#121314",
"brightGreen": "#121314",
"brightYellow": "#121314",
"brightBlue": "#121314",
"brightPurple": "#121314",
"brightCyan": "#121314",
"brightWhite": "#121314"
},
{
"name": "schemeWithoutCursorColor"
"name": "schemeWithoutCursorColor",
"black": "#121314",
"red": "#121314",
"green": "#121314",
"yellow": "#121314",
"blue": "#121314",
"purple": "#121314",
"cyan": "#121314",
"white": "#121314",
"brightBlack": "#121314",
"brightRed": "#121314",
"brightGreen": "#121314",
"brightYellow": "#121314",
"brightBlue": "#121314",
"brightPurple": "#121314",
"brightCyan": "#121314",
"brightWhite": "#121314"
}
]
})" };
CascadiaSettings settings{ til::u8u16(settings0String) };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settings0String);
VERIFY_ARE_EQUAL(6u, settings.ActiveProfiles().Size());
VERIFY_ARE_EQUAL(2u, settings.GlobalSettings().ColorSchemes().Size());
VERIFY_ARE_EQUAL(6u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(2u, settings->GlobalSettings().ColorSchemes().Size());
auto createTerminalSettings = [&](const auto& profile, const auto& schemes) {
auto terminalSettings{ winrt::make_self<implementation::TerminalSettings>() };
@@ -554,12 +790,14 @@ namespace SettingsModelLocalTests
return terminalSettings;
};
auto terminalSettings0 = createTerminalSettings(settings.ActiveProfiles().GetAt(0), settings.GlobalSettings().ColorSchemes());
auto terminalSettings1 = createTerminalSettings(settings.ActiveProfiles().GetAt(1), settings.GlobalSettings().ColorSchemes());
auto terminalSettings2 = createTerminalSettings(settings.ActiveProfiles().GetAt(2), settings.GlobalSettings().ColorSchemes());
auto terminalSettings3 = createTerminalSettings(settings.ActiveProfiles().GetAt(3), settings.GlobalSettings().ColorSchemes());
auto terminalSettings4 = createTerminalSettings(settings.ActiveProfiles().GetAt(4), settings.GlobalSettings().ColorSchemes());
auto terminalSettings5 = createTerminalSettings(settings.ActiveProfiles().GetAt(5), settings.GlobalSettings().ColorSchemes());
const auto activeProfiles = settings->ActiveProfiles();
const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes);
const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes);
const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes);
const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes);
const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes);
const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes);
VERIFY_ARE_EQUAL(ARGB(0, 0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme
VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default
@@ -571,7 +809,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestCommandlineToTitlePromotion()
{
const std::string settingsJson{ R"(
static constexpr std::string_view settingsJson{ R"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [
@@ -587,65 +825,63 @@ namespace SettingsModelLocalTests
} }
})" };
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
CascadiaSettings settings{ til::u8u16(settingsJson) };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
{ // just a profile (profile wins)
NewTerminalArgs args{};
args.Profile(L"profile0");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle());
}
{ // profile and command line -> no promotion (profile wins)
NewTerminalArgs args{};
args.Profile(L"profile0");
args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle());
}
{ // just a title -> it is propagated
NewTerminalArgs args{};
args.TabTitle(L"Analog Kid");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"Analog Kid", settingsStruct.DefaultSettings().StartingTitle());
}
{ // title and command line -> no promotion
NewTerminalArgs args{};
args.TabTitle(L"Digital Man");
args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"Digital Man", settingsStruct.DefaultSettings().StartingTitle());
}
{ // just a commandline -> promotion
NewTerminalArgs args{};
args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle());
}
// various typesof commandline follow
{
NewTerminalArgs args{};
args.Commandline(L"foo.exe bar");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle());
}
{
NewTerminalArgs args{};
args.Commandline(L"\"foo exe.exe\" bar");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo exe.exe", settingsStruct.DefaultSettings().StartingTitle());
}
{
NewTerminalArgs args{};
args.Commandline(L"\"\" grand designs");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle());
}
{
NewTerminalArgs args{};
args.Commandline(L" imagine a man");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle());
}
}

View File

@@ -715,7 +715,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(SplitType::Manual, myArgs.SplitMode());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -735,7 +735,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Horizontal, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(SplitType::Manual, myArgs.SplitMode());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -757,7 +757,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Vertical, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(SplitType::Manual, myArgs.SplitMode());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -799,7 +799,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
@@ -828,7 +828,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Horizontal, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, myArgs.SplitDirection());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
@@ -857,7 +857,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
@@ -1031,9 +1031,11 @@ namespace TerminalAppLocalTests
// The first action is going to always be a new-tab action
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
auto actionAndArgs = appArgs._startupActions.at(1);
const auto actionAndArgs = appArgs._startupActions.at(1);
VERIFY_ARE_EQUAL(ShortcutAction::NextTab, actionAndArgs.Action());
VERIFY_IS_NULL(actionAndArgs.Args());
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
const auto myArgs = actionAndArgs.Args().as<NextTabArgs>();
VERIFY_ARE_EQUAL(TabSwitcherMode::Disabled, myArgs.SwitcherMode().Value());
}
{
AppCommandlineArgs appArgs{};
@@ -1047,7 +1049,9 @@ namespace TerminalAppLocalTests
auto actionAndArgs = appArgs._startupActions.at(1);
VERIFY_ARE_EQUAL(ShortcutAction::PrevTab, actionAndArgs.Action());
VERIFY_IS_NULL(actionAndArgs.Args());
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
const auto myArgs = actionAndArgs.Args().as<PrevTabArgs>();
VERIFY_ARE_EQUAL(TabSwitcherMode::Disabled, myArgs.SwitcherMode().Value());
}
{
AppCommandlineArgs appArgs{};
@@ -1779,7 +1783,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5f, myArgs.SplitSize());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -1799,7 +1803,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.3f, myArgs.SplitSize());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -1820,7 +1824,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.3f, myArgs.SplitSize());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -1830,7 +1834,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.5f, myArgs.SplitSize());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -1852,7 +1856,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.3f, myArgs.SplitSize());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}
@@ -1862,7 +1866,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_ARE_EQUAL(SplitState::Automatic, myArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, myArgs.SplitDirection());
VERIFY_ARE_EQUAL(0.7f, myArgs.SplitSize());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
}

View File

@@ -16,6 +16,31 @@ using namespace winrt::Microsoft::Terminal::Control;
namespace TerminalAppLocalTests
{
static constexpr std::wstring_view inboxSettings{ LR"({
"schemes": [{
"name": "Campbell",
"foreground": "#CCCCCC",
"background": "#0C0C0C",
"cursorColor": "#FFFFFF",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
}]
})" };
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
// an updated TAEF that will let us install framework packages when the test
@@ -79,7 +104,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile.
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -107,14 +132,10 @@ namespace TerminalAppLocalTests
"iterateOn": "profiles",
"command": { "action": "splitPane", "profile": "${profile.name}" }
},
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@@ -132,7 +153,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -156,7 +177,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -174,7 +195,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -192,7 +213,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -207,7 +228,7 @@ namespace TerminalAppLocalTests
// For this test, put an iterable command without a given `name` to
// replace. When we expand it, it should still work.
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -234,14 +255,10 @@ namespace TerminalAppLocalTests
"iterateOn": "profiles",
"command": { "action": "splitPane", "profile": "${profile.name}" }
},
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@@ -259,7 +276,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -283,7 +300,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -301,7 +318,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -319,7 +336,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -335,7 +352,7 @@ namespace TerminalAppLocalTests
// cause bad json to be filled in. Something like a profile with a name
// of "Foo\"", so the trailing '"' might break the json parsing.
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -363,14 +380,10 @@ namespace TerminalAppLocalTests
"iterateOn": "profiles",
"command": { "action": "splitPane", "profile": "${profile.name}" }
},
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@@ -388,7 +401,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -412,7 +425,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -430,7 +443,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -448,7 +461,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -468,7 +481,7 @@ namespace TerminalAppLocalTests
// ├─ first.com
// └─ second.com
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -504,11 +517,10 @@ namespace TerminalAppLocalTests
}
]
},
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@@ -558,7 +570,7 @@ namespace TerminalAppLocalTests
// ├─ child1
// └─ child2
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -599,11 +611,10 @@ namespace TerminalAppLocalTests
},
]
},
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@@ -680,18 +691,18 @@ namespace TerminalAppLocalTests
// <Command Palette>
// ├─ profile0...
// | ├─ Split pane, profile: profile0
// | ├─ Split pane, direction: vertical, profile: profile0
// | └─ Split pane, direction: horizontal, profile: profile0
// | ├─ Split pane, direction: right, profile: profile0
// | └─ Split pane, direction: down, profile: profile0
// ├─ profile1...
// | ├─Split pane, profile: profile1
// | ├─Split pane, direction: vertical, profile: profile1
// | └─Split pane, direction: horizontal, profile: profile1
// | ├─Split pane, direction: right, profile: profile1
// | └─Split pane, direction: down, profile: profile1
// └─ profile2...
// ├─ Split pane, profile: profile2
// ├─ Split pane, direction: vertical, profile: profile2
// └─ Split pane, direction: horizontal, profile: profile2
// ├─ Split pane, direction: right, profile: profile2
// └─ Split pane, direction: down, profile: profile2
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -719,15 +730,14 @@ namespace TerminalAppLocalTests
"name": "${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "auto" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } }
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "right" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "down" } }
]
}
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@@ -762,7 +772,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -773,7 +783,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: horizontal, profile: {}", name) };
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: down, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
@@ -783,7 +793,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -794,7 +804,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: vertical, profile: {}", name) };
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: right, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
@@ -804,7 +814,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -828,7 +838,7 @@ namespace TerminalAppLocalTests
// ├─ Profile 2
// └─ Profile 3
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -860,11 +870,10 @@ namespace TerminalAppLocalTests
}
]
}
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@@ -915,18 +924,18 @@ namespace TerminalAppLocalTests
// └─ New Pane...
// ├─ profile0...
// | ├─ Split automatically
// | ├─ Split vertically
// | └─ Split horizontally
// | ├─ Split right
// | └─ Split down
// ├─ profile1...
// | ├─ Split automatically
// | ├─ Split vertically
// | └─ Split horizontally
// | ├─ Split right
// | └─ Split down
// └─ profile2...
// ├─ Split automatically
// ├─ Split vertically
// └─ Split horizontally
// ├─ Split right
// └─ Split down
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -957,17 +966,16 @@ namespace TerminalAppLocalTests
"name": "${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "auto" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } }
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "right" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "down" } }
]
}
]
}
],
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
]
})" };
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@@ -1010,7 +1018,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -1021,7 +1029,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: horizontal, profile: {}", name) };
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: down, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
@@ -1031,7 +1039,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -1042,7 +1050,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: vertical, profile: {}", name) };
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: right, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
@@ -1052,7 +1060,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -1071,7 +1079,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile.
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -1094,9 +1102,72 @@ namespace TerminalAppLocalTests
}
],
"schemes": [
{ "name": "scheme_0" },
{ "name": "scheme_1" },
{ "name": "scheme_2" },
{
"name": "Campbell",
"foreground": "#CCCCCC",
"background": "#0C0C0C",
"cursorColor": "#FFFFFF",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
},
{
"name": "Campbell PowerShell",
"foreground": "#CCCCCC",
"background": "#012456",
"cursorColor": "#FFFFFF",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
},
{
"name": "Vintage",
"foreground": "#C0C0C0",
"background": "#000000",
"cursorColor": "#FFFFFF",
"black": "#000000",
"red": "#800000",
"green": "#008000",
"yellow": "#808000",
"blue": "#000080",
"purple": "#800080",
"cyan": "#008080",
"white": "#C0C0C0",
"brightBlack": "#808080",
"brightRed": "#FF0000",
"brightGreen": "#00FF00",
"brightYellow": "#FFFF00",
"brightBlue": "#0000FF",
"brightPurple": "#FF00FF",
"brightCyan": "#00FFFF",
"brightWhite": "#FFFFFF"
}
],
"actions": [
{
@@ -1107,11 +1178,7 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings{ til::u8u16(settingsJson) };
// Since at least one profile does not reference a color scheme,
// we add a warning saying "the color scheme is unknown"
VERIFY_ARE_EQUAL(1u, settings.Warnings().Size());
CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@@ -1127,7 +1194,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
@@ -1139,8 +1206,6 @@ namespace TerminalAppLocalTests
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
// This is the same warning as above
VERIFY_ARE_EQUAL(1u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
// Yes, this test is testing splitPane with profiles named after each
@@ -1148,7 +1213,7 @@ namespace TerminalAppLocalTests
// just easy tests to write.
{
auto command = expandedCommands.Lookup(L"iterable command scheme_0");
auto command = expandedCommands.Lookup(L"iterable command Campbell");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
@@ -1156,17 +1221,17 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"scheme_0", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"Campbell", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command scheme_1");
auto command = expandedCommands.Lookup(L"iterable command Campbell PowerShell");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
@@ -1174,17 +1239,17 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"scheme_1", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"Campbell PowerShell", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command scheme_2");
auto command = expandedCommands.Lookup(L"iterable command Vintage");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
@@ -1192,13 +1257,13 @@ namespace TerminalAppLocalTests
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"scheme_2", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"Vintage", realArgs.TerminalArgs().Profile());
}
}

View File

@@ -311,7 +311,7 @@ namespace TerminalAppLocalTests
// TerminalPage and not only create them successfully, but also create a
// tab using those settings successfully.
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -328,7 +328,7 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
// This is super wacky, but we can't just initialize the
@@ -357,7 +357,7 @@ namespace TerminalAppLocalTests
//
// Created to test GH#2455
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -374,7 +374,7 @@ namespace TerminalAppLocalTests
]
})" };
const std::string settingsJson1{ R"(
static constexpr std::wstring_view settingsJson1{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -386,10 +386,10 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) };
CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@@ -444,7 +444,7 @@ namespace TerminalAppLocalTests
//
// Created to test GH#2455
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -461,7 +461,7 @@ namespace TerminalAppLocalTests
]
})" };
const std::string settingsJson1{ R"(
static constexpr std::wstring_view settingsJson1{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@@ -473,10 +473,10 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) };
CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@@ -508,7 +508,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
result = RunOnUIThread([&page]() {
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr);
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@@ -526,7 +526,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
result = RunOnUIThread([&page]() {
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr);
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@@ -558,7 +558,7 @@ namespace TerminalAppLocalTests
// - The initialized TerminalPage, ready to use.
winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> TabTests::_commonSetup()
{
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"showTabsInTitlebar": false,
@@ -659,7 +659,7 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@@ -751,7 +751,7 @@ namespace TerminalAppLocalTests
});
VERIFY_SUCCEEDED(result);
Log::Comment(L"Move focus. This will cause us to un-zoom.");
Log::Comment(L"Move focus. We should still be zoomed.");
result = RunOnUIThread([&page]() {
// Set up action
MoveFocusArgs args{ FocusDirection::Left };
@@ -761,7 +761,7 @@ namespace TerminalAppLocalTests
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
VERIFY_SUCCEEDED(result);
}
@@ -844,7 +844,7 @@ namespace TerminalAppLocalTests
// | 1 | 2 |
// | | |
// -------------------
page->_SplitPane(SplitState::Vertical, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Right, SplitType::Duplicate, 0.5f, nullptr);
secondId = tab->_activePane->Id().value();
});
Sleep(250);
@@ -862,7 +862,7 @@ namespace TerminalAppLocalTests
// | 3 | |
// | | |
// -------------------
page->_SplitPane(SplitState::Horizontal, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr);
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
// Split again to make the 3rd tab
thirdId = tab->_activePane->Id().value();
@@ -882,7 +882,7 @@ namespace TerminalAppLocalTests
// | 3 | 4 |
// | | |
// -------------------
page->_SplitPane(SplitState::Horizontal, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr);
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
fourthId = tab->_activePane->Id().value();
});
@@ -1357,7 +1357,8 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
// And we should have stored a function to revert the change.
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
});
TestOnUIThread([&page]() {
@@ -1383,7 +1384,8 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
// After preview there should be no more restore functions to execute.
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
});
}
@@ -1428,7 +1430,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
});
TestOnUIThread([&page]() {
@@ -1451,7 +1452,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be the same as it originally was");
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
});
}
@@ -1498,7 +1498,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
});
TestOnUIThread([&page]() {
@@ -1522,7 +1521,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
});
TestOnUIThread([&page]() {
@@ -1548,7 +1546,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed");
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
});
}

View File

@@ -92,11 +92,11 @@
<!-- From Microsoft.UI.Xaml.targets -->
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
<_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot>
<_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot>
</PropertyGroup>
<!-- We actually can just straight up reference MUX here, it's fine -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
</Project>

View File

@@ -123,7 +123,7 @@
</Reference>
</ItemGroup>
<Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)\src\common.build.post.props" />

View File

@@ -549,11 +549,11 @@ try
if (multiClickMapper == 3)
{
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansionMode::Line);
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Line);
}
else if (multiClickMapper == 2)
{
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansionMode::Word);
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Word);
}
else
{

View File

@@ -0,0 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "GetWindowLayoutArgs.h"
#include "GetWindowLayoutArgs.g.cpp"

View File

@@ -0,0 +1,32 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Class Name:
- GetWindowLayoutArgs.h
Abstract:
- This is a helper class for getting the window layout from a peasant.
Depending on if we are running on the monarch or on a peasant we might need
to switch what thread we are executing on. This gives us the option of
either returning the json result synchronously, or as a promise.
--*/
#pragma once
#include "GetWindowLayoutArgs.g.h"
#include "../cascadia/inc/cppwinrt_utils.h"
namespace winrt::Microsoft::Terminal::Remoting::implementation
{
struct GetWindowLayoutArgs : public GetWindowLayoutArgsT<GetWindowLayoutArgs>
{
WINRT_PROPERTY(winrt::hstring, WindowLayoutJson, L"");
WINRT_PROPERTY(winrt::Windows::Foundation::IAsyncOperation<winrt::hstring>, WindowLayoutJsonAsync, nullptr)
};
}
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
{
BASIC_FACTORY(GetWindowLayoutArgs);
}

View File

@@ -12,7 +12,6 @@
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="Monarch.h">
@@ -36,6 +35,12 @@
<ClInclude Include="WindowActivatedArgs.h">
<DependentUpon>Peasant.idl</DependentUpon>
</ClInclude>
<ClInclude Include="GetWindowLayoutArgs.h">
<DependentUpon>Peasant.idl</DependentUpon>
</ClInclude>
<ClInclude Include="QuitAllRequestedArgs.h">
<DependentUpon>Monarch.idl</DependentUpon>
</ClInclude>
<ClInclude Include="pch.h" />
<ClInclude Include="MonarchFactory.h" />
<ClInclude Include="Peasant.h">
@@ -71,6 +76,12 @@
<ClCompile Include="WindowActivatedArgs.cpp">
<DependentUpon>Peasant.idl</DependentUpon>
</ClCompile>
<ClCompile Include="GetWindowLayoutArgs.cpp">
<DependentUpon>Peasant.idl</DependentUpon>
</ClCompile>
<ClCompile Include="QuitAllRequestedArgs.cpp">
<DependentUpon>Monarch.idl</DependentUpon>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
@@ -128,6 +139,5 @@
</ItemDefinitionGroup>
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>
</Project>

View File

@@ -6,6 +6,7 @@
#include "Monarch.h"
#include "CommandlineArgs.h"
#include "FindTargetWindowArgs.h"
#include "QuitAllRequestedArgs.h"
#include "ProposeCommandlineResult.h"
#include "Monarch.g.cpp"
@@ -50,6 +51,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - Add the given peasant to the list of peasants we're tracking. This
// Peasant may have already been assigned an ID. If it hasn't, then give
// it an ID.
// - NB: this takes a unique_lock on _peasantsMutex.
// Arguments:
// - peasant: the new Peasant to track.
// Return Value:
@@ -71,19 +73,37 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
// Peasant already had an ID (from an older monarch). Leave that one
// be. Make sure that the next peasant's ID is higher than it.
_nextPeasantID = providedID >= _nextPeasantID ? providedID + 1 : _nextPeasantID;
// If multiple peasants are added concurrently we keep trying to update
// until we get to set the new id.
uint64_t current;
do
{
current = _nextPeasantID.load(std::memory_order_relaxed);
} while (current <= providedID && !_nextPeasantID.compare_exchange_weak(current, providedID + 1, std::memory_order_relaxed));
}
auto newPeasantsId = peasant.GetID();
// Keep track of which peasant we are
// SAFETY: this is only true for one peasant, and each peasant
// is only added to a monarch once, so we do not need synchronization here.
if (peasant.GetPID() == _ourPID)
{
_ourPeasantId = newPeasantsId;
}
// Add an event listener to the peasant's WindowActivated event.
peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated });
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
peasant.RenameRequested({ this, &Monarch::_renameRequested });
peasant.ShowTrayIconRequested([this](auto&&, auto&&) { _ShowTrayIconRequestedHandlers(*this, nullptr); });
peasant.HideTrayIconRequested([this](auto&&, auto&&) { _HideTrayIconRequestedHandlers(*this, nullptr); });
peasant.ShowNotificationIconRequested([this](auto&&, auto&&) { _ShowNotificationIconRequestedHandlers(*this, nullptr); });
peasant.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll });
_peasants[newPeasantsId] = peasant;
{
std::unique_lock lock{ _peasantsMutex };
_peasants[newPeasantsId] = peasant;
}
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_AddPeasant",
@@ -91,6 +111,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingUInt64(newPeasantsId, "peasantID", "the ID of the new peasant"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_WindowCreatedHandlers(nullptr, nullptr);
return newPeasantsId;
}
catch (...)
@@ -107,6 +129,100 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
}
}
// Method Description:
// - Gives the host process an opportunity to run any pre-close logic then
// requests all peasants to close.
// Arguments:
// - <none> used
// Return Value:
// - <none>
winrt::fire_and_forget Monarch::_handleQuitAll(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
// Let the process hosting the monarch run any needed logic before
// closing all windows.
auto args = winrt::make_self<implementation::QuitAllRequestedArgs>();
_QuitAllRequestedHandlers(*this, *args);
if (const auto action = args->BeforeQuitAllAction())
{
co_await action;
}
_quitting.store(true);
// Tell all peasants to exit.
const auto callback = [&](const auto& id, const auto& p) {
// We want to tell our peasant to quit last, so that we don't try
// to perform a bunch of elections on quit.
if (id != _ourPeasantId)
{
p.Quit();
}
};
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_handleQuitAll_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not close"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(callback, onError);
{
std::shared_lock lock{ _peasantsMutex };
const auto peasantSearch = _peasants.find(_ourPeasantId);
if (peasantSearch != _peasants.end())
{
peasantSearch->second.Quit();
}
else
{
// Somehow we don't have our own peasant, this should never happen.
// We are trying to quit anyways so just fail here.
assert(peasantSearch != _peasants.end());
}
}
}
// Method Description:
// - Tells the monarch that a peasant is being closed.
// - NB: this (separately) takes unique locks on _peasantsMutex and
// _mruPeasantsMutex.
// Arguments:
// - peasantId: the id of the peasant
// Return Value:
// - <none>
void Monarch::SignalClose(const uint64_t peasantId)
{
// If we are quitting we don't care about maintaining our list of
// peasants anymore, and don't need to notify the host that something
// changed.
if (_quitting.load(std::memory_order_acquire))
{
return;
}
_clearOldMruEntries({ peasantId });
{
std::unique_lock lock{ _peasantsMutex };
_peasants.erase(peasantId);
}
_WindowClosedHandlers(nullptr, nullptr);
}
// Method Description:
// - Counts the number of living peasants.
// Arguments:
// - <none>
// Return Value:
// - the number of active peasants.
uint64_t Monarch::GetNumberOfPeasants()
{
std::shared_lock lock{ _peasantsMutex };
return _peasants.size();
}
// Method Description:
// - Event handler for the Peasant::WindowActivated event. Used as an
// opportunity for us to update our internal stack of the "most recent
@@ -125,16 +241,25 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// Method Description:
// - Lookup a peasant by its ID. If the peasant has died, this will also
// remove the peasant from our list of peasants.
// - NB: this (separately) takes unique locks on _peasantsMutex and
// _mruPeasantsMutex.
// Arguments:
// - peasantID: The ID Of the peasant to find
// - clearMruPeasantOnFailure: When true this function will handle clearing
// from _mruPeasants if a peasant was not found, otherwise the caller is
// expected to handle that cleanup themselves.
// Return Value:
// - the peasant if it exists in our map, otherwise null
Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID)
Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID, bool clearMruPeasantOnFailure)
{
try
{
const auto peasantSearch = _peasants.find(peasantID);
auto maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
IPeasant maybeThePeasant = nullptr;
{
std::shared_lock lock{ _peasantsMutex };
const auto peasantSearch = _peasants.find(peasantID);
maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
}
// Ask the peasant for their PID. This will validate that they're
// actually still alive.
if (maybeThePeasant)
@@ -146,12 +271,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// Remove the peasant from the list of peasants
_peasants.erase(peasantID);
// Remove the peasant from the list of MRU windows. They're dead.
// They can't be the MRU anymore.
_clearOldMruEntries(peasantID);
// Remove the peasant from the list of peasants
{
std::unique_lock lock{ _peasantsMutex };
_peasants.erase(peasantID);
}
if (clearMruPeasantOnFailure)
{
// Remove the peasant from the list of MRU windows. They're dead.
// They can't be the MRU anymore.
_clearOldMruEntries({ peasantID });
}
return nullptr;
}
}
@@ -172,39 +304,27 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return 0;
}
std::vector<uint64_t> peasantsToErase{};
uint64_t result = 0;
for (const auto& [id, p] : _peasants)
{
try
{
auto otherName = p.WindowName();
if (otherName == name)
{
result = id;
break;
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// Normally, we'd just erase the peasant here. However, we can't
// erase from the map while we're iterating over it like this.
// Instead, pull a good ole Java and collect this id for removal
// later.
peasantsToErase.push_back(id);
}
}
// Remove the dead peasants we came across while iterating.
for (const auto& id : peasantsToErase)
{
// Remove the peasant from the list of peasants
_peasants.erase(id);
// Remove the peasant from the list of MRU windows. They're dead.
// They can't be the MRU anymore.
_clearOldMruEntries(id);
}
const auto callback = [&](const auto& id, const auto& p) {
auto otherName = p.WindowName();
if (otherName == name)
{
result = id;
return false;
}
return true;
};
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_lookupPeasantIdForName_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not get the name of"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(callback, onError);
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_lookupPeasantIdForName",
@@ -233,6 +353,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - <none>
void Monarch::HandleActivatePeasant(const Remoting::WindowActivatedArgs& args)
{
if (args == nullptr)
{
// MSFT:35731327, GH #12624. There's a chance that the way the
// window gets set up for defterm, the ActivatedArgs haven't been
// created for this window yet. Check here and just ignore them if
// they're null. They'll come back with real args soon
return;
}
// Start by making a local copy of these args. It's easier for us if our
// tracking of these args is all in-proc. That way, the only thing that
// could fail due to the peasant dying is _this first copy_.
@@ -256,56 +384,71 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - Helper for removing a peasant from the list of MRU peasants. We want to
// do this both when the peasant dies, and also when the peasant is newly
// activated (so that we don't leave an old entry for it in the list).
// - NB: This takes a unique lock on _mruPeasantsMutex.
// Arguments:
// - peasantID: The ID of the peasant to remove from the MRU list
// - peasantIds: The list of peasant IDs to remove from the MRU list
// Return Value:
// - <none>
void Monarch::_clearOldMruEntries(const uint64_t peasantID)
void Monarch::_clearOldMruEntries(const std::unordered_set<uint64_t>& peasantIds)
{
auto result = std::find_if(_mruPeasants.begin(),
_mruPeasants.end(),
[peasantID](auto&& other) {
return peasantID == other.PeasantID();
});
if (result != std::end(_mruPeasants))
if (peasantIds.size() == 0)
{
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_RemovedPeasantFromDesktop",
TraceLoggingUInt64(peasantID, "peasantID", "The ID of the peasant"),
TraceLoggingGuid(result->DesktopID(), "desktopGuid", "The GUID of the previous desktop the window was on"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_mruPeasants.erase(result);
return;
}
std::unique_lock lock{ _mruPeasantsMutex };
auto partition = std::remove_if(_mruPeasants.begin(), _mruPeasants.end(), [&](const auto& p) {
const auto id = p.PeasantID();
// remove the element if it was found in the list to erase.
if (peasantIds.count(id) == 1)
{
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_RemovedPeasantFromDesktop",
TraceLoggingUInt64(id, "peasantID", "The ID of the peasant"),
TraceLoggingGuid(p.DesktopID(), "desktopGuid", "The GUID of the previous desktop the window was on"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return true;
}
return false;
});
// Remove everything that was in the list
_mruPeasants.erase(partition, _mruPeasants.end());
}
// Method Description:
// - Actually handle inserting the WindowActivatedArgs into our list of MRU windows.
// - NB: this takes a unique_lock on _mruPeasantsMutex.
// Arguments:
// - localArgs: an in-proc WindowActivatedArgs that we should add to our list of MRU windows.
// Return Value:
// - <none>
void Monarch::_doHandleActivatePeasant(const winrt::com_ptr<implementation::WindowActivatedArgs>& localArgs)
{
// We're sure that localArgs isn't null here, we checked before in our
// one caller (in Monarch::HandleActivatePeasant)
const auto newLastActiveTime = localArgs->ActivatedTime().time_since_epoch().count();
// * Check all the current lists to look for this peasant.
// remove it from any where it exists.
_clearOldMruEntries(localArgs->PeasantID());
_clearOldMruEntries({ localArgs->PeasantID() });
// * If the current desktop doesn't have a vector, add one.
const auto desktopGuid{ localArgs->DesktopID() };
// * Add this args list. By using lower_bound with insert, we can get it
// into exactly the right spot, without having to re-sort the whole
// array.
_mruPeasants.insert(std::lower_bound(_mruPeasants.begin(),
_mruPeasants.end(),
*localArgs,
[](const auto& first, const auto& second) { return first.ActivatedTime() > second.ActivatedTime(); }),
*localArgs);
{
std::unique_lock lock{ _mruPeasantsMutex };
// * Add this args list. By using lower_bound with insert, we can get it
// into exactly the right spot, without having to re-sort the whole
// array.
_mruPeasants.insert(std::lower_bound(_mruPeasants.begin(),
_mruPeasants.end(),
*localArgs,
[](const auto& first, const auto& second) { return first.ActivatedTime() > second.ActivatedTime(); }),
*localArgs);
}
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_SetMostRecentPeasant",
@@ -319,6 +462,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// Method Description:
// - Retrieves the ID of the MRU peasant window. If requested, will limit
// the search to windows that are on the current desktop.
// - NB: This method will hold a shared lock on _mruPeasantsMutex and
// potentially a unique_lock on _peasantsMutex at the same time.
// Separately it might hold a unique_lock on _mruPeasantsMutex.
// Arguments:
// - limitToCurrentDesktop: if true, only return the MRU peasant that's
// actually on the current desktop.
@@ -331,8 +477,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - the ID of the most recent peasant, otherwise 0 if we could not find one.
uint64_t Monarch::_getMostRecentPeasantID(const bool limitToCurrentDesktop, const bool ignoreQuakeWindow)
{
std::shared_lock lock{ _mruPeasantsMutex };
if (_mruPeasants.empty())
{
// unlock the mruPeasants mutex to make sure we can't deadlock here.
lock.unlock();
// Only need a shared lock for read
std::shared_lock peasantsLock{ _peasantsMutex };
// We haven't yet been told the MRU peasant. Just use the first one.
// This is just gonna be a random one, but really shouldn't happen
// in practice. The WindowManager should set the MRU peasant
@@ -373,15 +524,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - If it isn't on the current desktop, we'll loop again, on the
// following peasant.
// * If we don't care, then we'll just return that one.
//
// We're not just using an iterator because the contents of the list
// might change while we're iterating here (if the peasant is dead we'll
// remove it from the list).
int positionInList = 0;
while (_mruPeasants.cbegin() + positionInList < _mruPeasants.cend())
uint64_t result = 0;
std::unordered_set<uint64_t> peasantsToErase{};
for (const auto& mruWindowArgs : _mruPeasants)
{
const auto mruWindowArgs{ *(_mruPeasants.begin() + positionInList) };
const auto peasant{ _getPeasant(mruWindowArgs.PeasantID()) };
// Try to get the peasant, but do not have _getPeasant clean up old
// _mruPeasants because we are iterating here.
// SAFETY: _getPeasant can take a unique_lock on _peasantsMutex if
// it detects a peasant is dead. Currently _getMostRecentPeasantId
// is the only method that holds a lock on both _mruPeasantsMutex and
// _peasantsMutex at the same time so there cannot be a deadlock here.
const auto peasant{ _getPeasant(mruWindowArgs.PeasantID(), false) };
if (!peasant)
{
TraceLoggingWrite(g_hRemotingProvider,
@@ -395,6 +548,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// We'll go through the loop again. We removed the current one
// at positionInList, so the next one in positionInList will be
// a new, different peasant.
peasantsToErase.emplace(mruWindowArgs.PeasantID());
continue;
}
@@ -432,7 +586,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
"true if this window was in fact on the current desktop"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return mruWindowArgs.PeasantID();
result = mruWindowArgs.PeasantID();
break;
}
// If this window wasn't on the current desktop, another one
// might be. We'll increment positionInList below, and try
@@ -446,20 +601,30 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return mruWindowArgs.PeasantID();
result = mruWindowArgs.PeasantID();
break;
}
positionInList++;
}
// Here, we've checked all the windows, and none of them was both alive
// and the most recent (on this desktop). Just return 0 - the caller
// will use this to create a new window.
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_getMostRecentPeasantID_NotFound",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
lock.unlock();
return 0;
if (peasantsToErase.size() > 0)
{
_clearOldMruEntries(peasantsToErase);
}
if (result == 0)
{
// Here, we've checked all the windows, and none of them was both alive
// and the most recent (on this desktop). Just return 0 - the caller
// will use this to create a new window.
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_getMostRecentPeasantID_NotFound",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
return result;
}
// Method Description:
@@ -613,39 +778,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return *result;
}
// Method Description:
// - Helper for doing something on each and every peasant, with no regard
// for if the peasant is living or dead.
// - We'll try calling callback on every peasant.
// - If any single peasant is dead, then we'll call errorCallback, and move on.
// - We're taking an errorCallback here, because the thing we usually want
// to do is TraceLog a message, but TraceLoggingWrite is actually a macro
// that _requires_ the second arg to be a string literal. It can't just be
// a variable.
// Arguments:
// - callback: The function to call on each peasant
// - errorCallback: The function to call if a peasant is dead.
// Return Value:
// - <none>
void Monarch::_forAllPeasantsIgnoringTheDead(std::function<void(const Remoting::IPeasant&, const uint64_t)> callback,
std::function<void(const uint64_t)> errorCallback)
{
for (const auto& [id, p] : _peasants)
{
try
{
callback(p, id);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// If this fails, we don't _really_ care. Just move on to the
// next one. Someone else will clean up the dead peasant.
errorCallback(id);
}
}
}
// Method Description:
// - This is an event handler for the IdentifyWindowsRequested event. A
// Peasant may raise that event if they want _all_ windows to identify
@@ -660,17 +792,18 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
// Notify all the peasants to display their ID.
auto callback = [](auto&& p, auto&& /*id*/) {
const auto callback = [&](const auto& /*id*/, const auto& p) {
p.DisplayWindowId();
};
auto onError = [](auto&& id) {
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_identifyWindows_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not identify"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forAllPeasantsIgnoringTheDead(callback, onError);
_forEachPeasant(callback, onError);
}
// Method Description:
@@ -812,48 +945,95 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - <none>
// Return Value:
// - A map of peasant IDs to their names.
Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> Monarch::GetPeasantNames()
Windows::Foundation::Collections::IVectorView<PeasantInfo> Monarch::GetPeasantInfos()
{
auto names = winrt::single_threaded_map<uint64_t, winrt::hstring>();
std::vector<uint64_t> peasantsToErase{};
for (const auto& [id, p] : _peasants)
std::vector<PeasantInfo> names;
{
try
{
names.Insert(id, p.WindowName());
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
peasantsToErase.push_back(id);
}
std::shared_lock lock{ _peasantsMutex };
names.reserve(_peasants.size());
}
// Remove the dead peasants we came across while iterating.
for (const auto& id : peasantsToErase)
{
_peasants.erase(id);
_clearOldMruEntries(id);
}
const auto func = [&](const auto& id, const auto& p) -> void {
names.push_back({ id, p.WindowName(), p.ActiveTabTitle() });
};
return names.GetView();
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_identifyWindows_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not identify"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(func, onError);
return winrt::single_threaded_vector<PeasantInfo>(std::move(names)).GetView();
}
bool Monarch::DoesQuakeWindowExist()
{
bool result = false;
const auto func = [&](const auto& /*id*/, const auto& p) {
if (p.WindowName() == QuakeWindowName)
{
result = true;
}
// continue if we didn't get a positive result
return !result;
};
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_DoesQuakeWindowExist_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not ask for its name"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(func, onError);
return result;
}
void Monarch::SummonAllWindows()
{
auto callback = [](auto&& p, auto&& /*id*/) {
const auto func = [&](const auto& /*id*/, const auto& p) {
SummonWindowBehavior args{};
args.ToggleVisibility(false);
p.Summon(args);
};
auto onError = [](auto&& id) {
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_SummonAll_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not summon"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forAllPeasantsIgnoringTheDead(callback, onError);
_forEachPeasant(func, onError);
}
// Method Description:
// - Ask all peasants to return their window layout as json
// Arguments:
// - <none>
// Return Value:
// - The collection of window layouts from each peasant.
Windows::Foundation::Collections::IVector<winrt::hstring> Monarch::GetAllWindowLayouts()
{
std::vector<winrt::hstring> vec;
auto callback = [&](const auto& /*id*/, const auto& p) {
vec.emplace_back(p.GetWindowLayout());
};
auto onError = [](auto&& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_GetAllWindowLayouts_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not get a window layout from"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(callback, onError);
return winrt::single_threaded_vector(std::move(vec));
}
}

View File

@@ -7,6 +7,7 @@
#include "Peasant.h"
#include "../cascadia/inc/cppwinrt_utils.h"
#include "WindowActivatedArgs.h"
#include <atomic>
// We sure different GUIDs here depending on whether we're running a Release,
// Preview, or Dev build. This ensures that different installs don't
@@ -27,7 +28,7 @@ constexpr GUID Monarch_clsid
0x7eb1,
0x4f3e,
{
0x85, 0xf5, 0x8b, 0xdd, 0x73, 0x86, 0xcc, 0xe3
0x85, 0xf5, 0x8b, 0xdd, 0x73, 0x86, 0xcc, 0xe4
}
};
@@ -47,38 +48,52 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
uint64_t GetPID();
uint64_t AddPeasant(winrt::Microsoft::Terminal::Remoting::IPeasant peasant);
void SignalClose(const uint64_t peasantId);
uint64_t GetNumberOfPeasants();
winrt::Microsoft::Terminal::Remoting::ProposeCommandlineResult ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
void HandleActivatePeasant(const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
void SummonWindow(const Remoting::SummonWindowSelectionArgs& args);
void SummonAllWindows();
Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> GetPeasantNames();
bool DoesQuakeWindowExist();
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
private:
uint64_t _ourPID;
uint64_t _nextPeasantID{ 1 };
uint64_t _thisPeasantID{ 0 };
std::atomic<uint64_t> _nextPeasantID{ 1 };
uint64_t _ourPeasantId{ 0 };
// When we're quitting we do not care as much about handling some events that we know will be triggered
std::atomic<bool> _quitting{ false };
winrt::com_ptr<IVirtualDesktopManager> _desktopManager{ nullptr };
std::unordered_map<uint64_t, winrt::Microsoft::Terminal::Remoting::IPeasant> _peasants;
std::vector<Remoting::WindowActivatedArgs> _mruPeasants;
// These should not be locked at the same time to prevent deadlocks
// unless they are both shared_locks.
std::shared_mutex _peasantsMutex{};
std::shared_mutex _mruPeasantsMutex{};
winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID);
winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID, bool clearMruPeasantOnFailure = true);
uint64_t _getMostRecentPeasantID(bool limitToCurrentDesktop, const bool ignoreQuakeWindow);
uint64_t _lookupPeasantIdForName(std::wstring_view name);
void _peasantWindowActivated(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
void _doHandleActivatePeasant(const winrt::com_ptr<winrt::Microsoft::Terminal::Remoting::implementation::WindowActivatedArgs>& args);
void _clearOldMruEntries(const uint64_t peasantID);
void _clearOldMruEntries(const std::unordered_set<uint64_t>& peasantIds);
void _forAllPeasantsIgnoringTheDead(std::function<void(const winrt::Microsoft::Terminal::Remoting::IPeasant&, const uint64_t)> callback,
std::function<void(const uint64_t)> errorCallback);
@@ -89,6 +104,87 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void _renameRequested(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
winrt::fire_and_forget _handleQuitAll(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args);
// Method Description:
// - Helper for doing something on each and every peasant.
// - We'll try calling func on every peasant.
// - If the return type of func is void, it will perform it for all peasants.
// - If the return type is a boolean, we'll break out of the loop once func
// returns false.
// - If any single peasant is dead, then we'll call onError and then add it to a
// list of peasants to clean up once the loop ends.
// - NB: this (separately) takes unique locks on _peasantsMutex and
// _mruPeasantsMutex.
// Arguments:
// - func: The function to call on each peasant
// - onError: The function to call if a peasant is dead.
// Return Value:
// - <none>
template<typename F, typename T>
void _forEachPeasant(F&& func, T&& onError)
{
using Map = decltype(_peasants);
using R = std::invoke_result_t<F, Map::key_type, Map::mapped_type>;
static constexpr auto IsVoid = std::is_void_v<R>;
std::unordered_set<uint64_t> peasantsToErase;
{
std::shared_lock lock{ _peasantsMutex };
for (const auto& [id, p] : _peasants)
{
try
{
if constexpr (IsVoid)
{
func(id, p);
}
else
{
if (!func(id, p))
{
break;
}
}
}
catch (const winrt::hresult_error& exception)
{
onError(id);
if (exception.code() == 0x800706ba) // The RPC server is unavailable.
{
peasantsToErase.emplace(id);
}
else
{
LOG_CAUGHT_EXCEPTION();
throw;
}
}
}
}
if (peasantsToErase.size() > 0)
{
// Don't hold a lock on _peasants and _mruPeasants at the same
// time to avoid deadlocks.
{
std::unique_lock lock{ _peasantsMutex };
for (const auto& id : peasantsToErase)
{
_peasants.erase(id);
}
}
_clearOldMruEntries(peasantsToErase);
// A peasant died, let the app host know that the number of
// windows has changed.
_WindowClosedHandlers(nullptr, nullptr);
}
}
friend class RemotingUnitTests::RemotingTests;
};
}

View File

@@ -31,21 +31,45 @@ namespace Microsoft.Terminal.Remoting
Windows.Foundation.IReference<UInt64> WindowID;
}
[default_interface] runtimeclass QuitAllRequestedArgs
{
QuitAllRequestedArgs();
Windows.Foundation.IAsyncAction BeforeQuitAllAction;
}
[default_interface] runtimeclass Monarch {
Monarch();
struct PeasantInfo
{
UInt64 Id;
String Name;
String TabTitle;
};
interface IMonarch
{
UInt64 GetPID();
UInt64 AddPeasant(IPeasant peasant);
UInt64 GetNumberOfPeasants();
ProposeCommandlineResult ProposeCommandline(CommandlineArgs args);
void HandleActivatePeasant(WindowActivatedArgs args);
void SummonWindow(SummonWindowSelectionArgs args);
void SignalClose(UInt64 peasantId);
void SummonAllWindows();
Windows.Foundation.Collections.IMapView<UInt64, String> GetPeasantNames { get; };
Boolean DoesQuakeWindowExist();
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos { get; };
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> ShowTrayIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideTrayIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowClosed;
event Windows.Foundation.TypedEventHandler<Object, QuitAllRequestedArgs> QuitAllRequested;
};
runtimeclass Monarch : [default] IMonarch
{
Monarch();
};
}

View File

@@ -5,6 +5,7 @@
#include "Peasant.h"
#include "CommandlineArgs.h"
#include "SummonWindowBehavior.h"
#include "GetWindowLayoutArgs.h"
#include "Peasant.g.cpp"
#include "../../types/inc/utils.hpp"
@@ -226,35 +227,87 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::RequestShowTrayIcon()
void Peasant::RequestShowNotificationIcon()
{
try
{
_ShowTrayIconRequestedHandlers(*this, nullptr);
_ShowNotificationIconRequestedHandlers(*this, nullptr);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_RequestShowTrayIcon",
"Peasant_RequestShowNotificationIcon",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::RequestHideTrayIcon()
void Peasant::RequestHideNotificationIcon()
{
try
{
_HideTrayIconRequestedHandlers(*this, nullptr);
_HideNotificationIconRequestedHandlers(*this, nullptr);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_RequestHideTrayIcon",
"Peasant_RequestHideNotificationIcon",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::RequestQuitAll()
{
try
{
_QuitAllRequestedHandlers(*this, nullptr);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_RequestQuit",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::Quit()
{
try
{
_QuitRequestedHandlers(*this, nullptr);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_Quit",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
// Method Description:
// - Request and return the window layout from the current TerminalPage
// Arguments:
// - <none>
// Return Value:
// - the window layout as a json string
hstring Peasant::GetWindowLayout()
{
auto args = winrt::make_self<implementation::GetWindowLayoutArgs>();
_GetWindowLayoutRequestedHandlers(nullptr, *args);
if (const auto op = args->WindowLayoutJsonAsync())
{
// This will fail if called on the UI thread, so the monarch should
// never set WindowLayoutJsonAsync.
auto str = op.get();
return str;
}
return args->WindowLayoutJson();
}
}

View File

@@ -28,13 +28,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void RequestIdentifyWindows();
void DisplayWindowId();
void RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
void RequestShowTrayIcon();
void RequestHideTrayIcon();
void RequestShowNotificationIcon();
void RequestHideNotificationIcon();
void RequestQuitAll();
void Quit();
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
winrt::hstring GetWindowLayout();
WINRT_PROPERTY(winrt::hstring, WindowName);
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs);
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs);
@@ -42,8 +48,11 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
private:
Peasant(const uint64_t testPID);

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