tl;dr: ~Apphost() may pump the message loop.
That's no bueno. See comments in the diff.
Additionally, this PR enables `_assertIsMainThread` in
release to trace down mysterious crashes in those builds.
tl;dr: Open/CloseClipboard are surprisingly not thread-safe.
## Validation Steps Performed
* Copy a large amount of text (>1MB)
* Run `edit.exe`
* Press and hold Ctrl+Shift+V
* Doesn't crash ✅
I legitimately cannot figure out how I forgot this. Bell should support
all the same validation as other media resources! Technically this means
you can set `bellSound` to `desktopWallpaper`, but... we'll pretend that
makes sense.
I reworked the viewmodel to be a little more sensible. It no longer
requires somebody else to check that its files exist. The settings UI
now also displays `File not found` in the _preview_ for the bell if it
is a single file which failed validation!
Test Impact: The LocalTests do not call `Initialize(HWND)`, so we would
fail on launch.
Also, we have `Create()` and `Initialize()` and `event Initialized` (the
last of which is not called from either of the first two...)
Reflect inbox changes to `onecore/windows/core/console/open`.
* eed3a6fa5 Merged PR 13076689: Update managed TAEF tests that exist in
GE branches to use the new publishing locations of TAEF's managed
reference binaries.
* 718d7d02d Merged PR 12483430: build console* with clang
Somebody internal is trying to build the console with Clang (which is
cool).
---------
Co-authored-by: Dragos Sambotin <dragoss@microsoft.com>
Co-authored-by: Phil Deets <pdeets@microsoft.com>
Interesting changes in this update:
- better support for `REFIID,IUnknown**` in `capture`
- `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS` for all SxS DLL loading
- `get_self` reading from classic COM interfaces (rather than WinRT
ones)
- better incremental builds by ignoring stale winmd files (see
microsoft/cppwinrt#1404)
- some ability to mix c++17 and c++20 static libraries
- better codegen for `consume` methods
This version of C++/WinRT is better about propagating `protected`
fields from the metadata into the C++ projections. This required
us to switch to the `I...Protected` interfaces for some things
we are _technically_ not allowed access to. We also had some
`overridable` (protected!) members of our own that needed undec-
oration.
The unfocused appearance section in the settings UI looks a little off.
Specifically, the header was too large (larger than the breadcrumbs!)
and the button was weirdly aligned.
This PR reduces the size of the header and creates a style in
CommonResources that manages it. This is the only place it's used, for
now. A vertical alignment was added to the "create appearance" and
"delete appearance" buttons to make them look better. The top margin of
the "Text" header was also removed so that there isn't an awkward gap in
the unfocused appearance section (the 32 that was there was moved to the
bottom of the control preview so that that area remains unaffected.)
Follow-up from #19001
## Summary of the Pull Request
Adds a telemetry provider to the Terminal.Settings.Editor project as
well as new telemetry events to track traffic through the settings UI.
Specifically, the following events were added:
- `NavigatedToPage`: Event emitted when the user navigates to a page in
the settings UI
- Has a `PageId` parameter that includes the identifier of the page that
was navigated to
- (conditionally added when PageId = `page.editColorScheme`)
`SchemeName` parameter tracks the name of the color scheme that's being
edited
- conditionally added when PageId = `page.extensions`:
- `ExtensionPackageCount`: The number of extension packages displayed
- `ProfilesModifiedCount`: The number of profiles modified by enabled
extensions
- `ProfilesAddedCount`: The number of profiles added by enabled
extensions
- `ColorSchemesAddedCount`: The number of color schemes added by enabled
extensions
- conditionally added when PageId = `page.extensions.extensionView`:
- `FragmentSource`: The source of the fragment included in this
extension package
- `FragmentCount`: The number of fragments included in this extension
package
- `Enabled`: The enabled status of the extension
- (conditionally added when PageID = `page.newTabMenu`) if the page is
representing a folder view
- conditionally added when PageID = `page.profile.*`:
- `IsProfileDefaults`: if the modified profile is the profile.defaults
object
- `ProfileGuid`: the guid of the profile that was navigated to
- `ProfileSource`: the source of the profile that was navigated to
- conditionally added when PageID = `page.profile` (aka the base profile
page):
- `Orphaned`: tracks if the profile was orphaned
- `Hidden`: tracks if the profile is hidden
- (conditionally added when PageID = `page.profile.appearance`)
`HasBackgroundImage`: `if the profile has a background image defined`
- (conditionally added when PageID = `page.profile.appearance`)
`HasUnfocusedAppearance`: `if the profile has an unfocused appearance
defined`
- `AddNewProfile`: Event emitted when the user adds a new profile
`IsExtensionView` parameter tracks if the page is representing a view of
an extension
- Has a `Type` parameter that represents the type of the creation method
(i.e. empty profile, duplicate)
- `ResetApplicationState`: Event emitted when the user resets their
application state (via the UI)
- `ResetToDefaultSettings`: Event emitted when the user resets their
settings to their default value (via the UI)
- `OpenJson`: Event emitted when the user clicks the Open JSON button in
the settings UI
- Has a `SettingsTarget` parameter that represents the target settings
file (i.e. settings.json vs defaults.json)
- `CreateUnfocusedAppearance`: Event emitted when the user creates an
unfocused appearance for a profile
- `IsProfileDefaults`: if the modified profile is the profile.defaults
object
- `ProfileGuid`: the guid of the profile that was navigated to
- `ProfileSource`: the source of the profile that was navigated to
- `DeleteProfile`: Event emitted when the user deletes a profile
- also includes `ProfileGuid`, `ProfileSource`, `Orphaned` from the
`NavigatedToPage` section above
The page ids can be reused later as a serialized reference to the page.
We already use the one for the extensions page for the "new" badge.
The Name, Source, and Commandline profile settings should not be allowed
to be set on the Profiles.Defaults object. This just enforces that by
clearing them (as is done with Guid).
These profile settings are omitted from the settings UI's profile
defaults page.
Closes#19202
You know how much I hate squirreling away information on objects we have
to pass halfway across the universe just to get back.
In this case, `StartingTitle` will always be the name of the profile. We
only used ProfileName in places where we _needed a Title_, so this makes
it much more obvious what we're doing.
## Summary of the Pull Request
Fixes a bug where copying and coloring selected text would be off by
one. This was introduced in #18106 when selection was updated to be
stored as an exclusive range. `Selection::_RegenerateSelectionSpans()`
was updated then, but copying text and coloring selection didn't rely on
selection spans.
Copying text relies on `GetSelectionAnchors()`. This function has now
been updated to increment the bottom-right point of the selection. This
way, `GetTextSpans()` operates on the expected _exclusive_ range.
Coloring selection relies on `TextBuffer::SearchText()`,
`TextBuffer::GetTextRects` and `GetSelectionSpans()`. Both
`Selection::ColorSelection()` were updated to use `rect` over
`inclusive_rect` to emphasize that they are exclusive ranges. Converting
between the two improves clarity and fixes the bug.
## References and Relevant Issues
Introduced in #18106
## Validation Steps Performed
Copying text works in the following scenarios:
✅ single line, left-to-right and right-to-left
✅ multi-line, diagonal directions
✅ block selection
Coloring text works in the following scenarios:
✅ctrl+# --> color instance
✅ctrl+shift+# --> color all instances
Closes#19053
Fixes a few issues with some telemetry events:
- The macro is organized as such: `TraceLoggingX(value, argName,
[argDescription])`. A few args had a description set on the spot where
the name should be. I added a name for a few of these.
- `TraceLoggingBool` --> `TraceLoggingInt32` for `themeChoice` (we
shouldn't be casting the evaluated int as a bool; it loses some of the
data we care about)
- improves the description for `themeChoice` to include information
about the legacy values
Checked through all our telemetry events and all of the args have a
proper name set. We tend to use `TraceLoggingValue` too which
automatically figures out the type that's being used, so that's also
handled.
`IsOn` is the blinker on/off state, which `IsVisible`
is the actual cursor visibility on/off state.
## Validation Steps Performed
* Run bash/zsh in WSL
* (Repeatedly) Quickly scroll right and press A-Z
* Scrolls to the left ✅
Automatically generates an "SSH" folder in the new tab menu that
contains all profiles generated by the SSH profile generator. This
folder is created if the SSH generator created some profiles and the
folder hasn't been created before. Detecting if the folder was generated
is done via the new `bool ApplicationState::SSHFolderGenerated`. The
logic is similar to `SettingsLoader::DisableDeletedProfiles()`.
Found a bug on new tab menu's folder inlining feature where we were
counting the number of raw entries to determine whether to inline or
not. Since the folder only contained the match profiles entry, this bug
made it so that the profile entries would always be inlined. The fix was
very simple: count the number of _resolved_ entries instead of the raw
entries. This can be pulled into its own PR and serviced, if desired.
## References and Relevant Issues
#18814#14042
## Validation Steps Performed
✅ Existing users get an SSH folder if profiles were generated
## PR Checklist
Closes#19043
Due to an unexpected decision on behalf of the Azure Artifacts folks,
the default view for a feed with upstream sources reports all packages,
even if they are not actually populated into the feed.
This results in (uncontrolled) 401 errors whenever a new package appears
upstream, because the feed tells our users and our build system that it
is available, but fails when the download actually begins because it is
not allowed to "write" the upstream version to the feed.
Windows 11 uses some additional signals to determine what the user cares
about and give it a bit of a QoS boost. One of those signals is whether
it is associated with a window that is in the foreground or which has
input focus.
Association today takes two forms:
- Process has a window which is in the foreground or which has input
focus
- Process has a *parent* that meets the above criterion.
Console applications that are spawned "inside" terminal by handoff do
not fall into either bucket. They don't have a window. Their parent is
`dllhost` or `explorer`, who is definitely not in focus.
We are piloting a new API that allows us to associate those processes
with Terminal's window.
When Terminal is in focus, it will attach every process from the active
tab to its QoS group. This means that whatever is running in that tab
is put into the "foreground" bucket, and everything running in other
background tabs is not.
When Terminal is out of focus, it attaches every process to its QoS
group. This ensures that they all go into the "background" bucket
together, following the window.
This extends our current behavior in conhost to scroll to the
cursor position when typing. This is especially relevant in WSL,
where this won't happen at all, otherwise.
Closes#18073
Closes MSFT:49027268
This reverts commit c55aca508beadebc080b0c76b7322de80a294968
because it is unaware of the VT state and may inject the DSR CPR
while e.g. a DCS is going on.
Reopens#18725
* Moves clipboard writing from `ControlCore` to `TerminalPage`.
This requires adding a bunch of event types and logic.
This is technically not needed anymore after changing the
direction of this PR, but I kept it because it's better.
* Add a `WarnAboutMultiLinePaste` enum to differentiate between
"paste without warning always/never/if-bracketed-paste-disabled".
Closes#13014
Closes https://github.com/microsoft/edit/issues/279
## Validation Steps Performed
* Launch Microsoft Edit and copy text with a trailing newline
* Paste it with Ctrl+Shift+V
* It's pasted as it was copied ✅
* Changing the setting to "always" always warns ✅
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
Closes#19153
## Validation Steps Performed
I tried reproducing the issue on Windows 10 and couldn't.
I'm not sure what I did wrong. But I tested it under a
debugger with VtPipeTerm and it wrote the sequences to stdout.
As explained in the diff itself.
Closes#13136
## Validation Steps Performed
* In conhost, with `wtd` not running, execute:
```pwsh
1..10 | % { wt -w 1 nt --title=$_ pwsh -NoExit -Command "Get-Date
-Format HH:mm:ss.ffff" }
```
* Every tab is up and running immediately ✅
This will help terminals with a reflow behavior unlike
the one implemented in ConPTY, such as VS Code.
Closes#18725
## Validation Steps Performed
* Tested under a debugger ✅
* Use PowerShell 5 and reflow lines in the ConPTY buffer until they're
pushed outside the top viewport. Then type something in the prompt.
Cursor is in a consistent position, even if slightly off. ✅
In #16172, we removed the propagation of the profile down into the
Terminal Pane Content.
It was holding on to the profile from the _old_ settings model (😱).
This also broke background image hot reload.
This pull request broadly rewrites how we handle all media resources in
the Terminal settings model.
## What is a media resource?
A media resource is any JSON property that refers to a file on disk,
including:
- `icon` on profile
- `backgroundImage` on profile (appearance)
- `pixelShaderPath` and `pixelShaderImagePath` on profile (appearance)
- `icon` on command and the new tab menu entries
The last two bullet points were newly discovered during the course of
this work.
## Description of Changes
In every place the settings model used to store a string for a media
path, it now stores an `IMediaResource`.
A media resource must be _resolved_ before it's used. When resolved, it
can report whether it is `Ok` (found, valid) and what the final
normalized path was.
This allows the settings model to apply some new behaviors.
One of those new behaviors is resolving media paths _relative to the
JSON file that referred to them._ This means fragments and user settings
can now contain _local_ images, pixel shaders and more and refer to them
by filename.
Relative path support requires us to track the path from which every
media resource "container" was read[^2]. For "big" objects like Profile,
we track it directly in the object and for each layer. This means that
fragments **updating** a profile pass their relative base path into the
mix. For some of the entries such as those in `newTabMenu`, we just wing
it (#19191). For everything that is recursively owned by a parent that
has a path (say each Command inside an ActionMap), we pass it in from
the parent during media resolution.
During resolution, we now track _exactly which layer_ an icon,
background image, or pixel shader path came from and read the "base
path" from only that layer. The base path is not inherited.
Another new behavior is in the handling of web and other URLs.
Canonical and a few other WSL distributors had to resort to web URLs for
icons because we did not support loading them from the package. Julia
tried to use `ms-appx://JuliaPackageNameHere/path/to/icon` for the same
reason. Neither was intended, and of the two the second _should_ have
worked but never could[^1].
For both `http(s?)` URLs and `ms-appx://` URLs which specify a package
name, we now strip everything except the filename. As an example...
If my fragment specifies `https://example.net/assets/foo.ico`, and my
fragment was loaded from `C:\Fragments`, Terminal will look *only* at
`C:\Fragments\foo.ico`.
This works today for Julia (they put their icon in the fragment folder
hoping that one day we would support this.) It will require some work
from existing WSL distributors.
I'm told that this is similar to how XML schema documents work.
Now, icons are special. They support _Emoji_ and _Segoe Icons_. This PR
adds an early pass to avoid resolving anything that looks like an
emoji.
This PR intentionally expands the heuristic definition of an emoji. It
used to only cover 1-2 code unit emoji, which prevented the use of any
emoji more complicated than "man in business suite levitating."
An icon path will now be considered an emoji or symbol icon if it is
composed of a single grapheme cluster (as measured by ICU.)
This is not perfect, as it errs on the side of allowing too many
things... but each of those things is technically a single grapheme
cluster and is a perfectly legal FontIcon ;)
Profile icons are _even more special_ than icons. They have an
additional fallback behavior which we had to preserve. When a profile
icon fails validation, or is expressly set to `null`, we fall back to
the EXE specified in the command line.
Because we do this fallback during resolution, _and the icon may be
inherited by any higher profile,_ we can only resolve it against the
commandline at the same level as the failed or nulled icon.
Therefore, if you specify `icon: null` in your `defaults` profile, it
will only ever resolve to `cmd.exe` for any profile that inherits it
(unless you change `defaults.commandline`).
This change expands support for the magic keywords `desktopWallpaper`
and `none` to all media paths (yes, even `pixelShaderPath`... but also,
`pixelShaderImagePath`!) It also expands support for _environment
variables_ to all of those places. Yes, we had like forty different
handlers for different types of string path. They are now uniform.
## Resource Validation
Media resources which are not found are "rejected". If a rejected
resource lives in _user_ settings, we will generate a warning and
display it.
In the future, we could detect this in the Settings UI and display a
warning inline.
## Surprises
I learned that `Windows.Foundation.Uri` parses file paths into `file://`
URIs, but does not offer you a way to get the original file path back
out. If you pass `C:\hello world`, _`Uri.Path`_ will return
`/C:/hello%20world`. I kid you not.
As a workaround, we bail out of URL handling if the `:` is too close to
the start (indicating an absolute file path).
## Testing
I added a narow test hook in the media resource resolver, which is
removed completely by link-time code generation. It is a real joy.
The test cases are all new and hopefully comprehensive.
Closes#19075Closes#16295Closes#10359 (except it doesn't support fonts)
Supersedes #16949 somewhat (`WT_SETTINGS_DIR`)
Refs #18679
Refs #19215 (future work)
Refs #19201 (future work)
Refs #19191 (future work)
[^1]: Handling a `ms-appx` path requires us to _add their package to our
dependency graph_ for the entire duration during which the resource will
be used. For us, that could be any time (like opening the command
palette for the first time!)
[^2]: We don't bother tracking where the defaults came from, because we
control everything about them.
We already have the logic to fall back when the setting is disabled, we
just _also_ had a terrible eventing architecture and never used the
`Title` getter that was smart enough to figure it out.
This pull request somewhat disentangles the mess that is title handling.
For example, TerminalPage had a facility to get its current title! It
was never used. Once we started using it, it wouldn't work for the
Settings page... because it only read the title out of the active
control.
Closes#12871Closes#19139 (superseded)
---------
Co-authored-by: techypanda <jonathan_wright@hotmail.com>
- Modify the cursor repositioning logic to check if a selection is in
progress
- Only reposition the cursor when the mouse is used for positioning, not
during selection operations
Closes#19181
You can now create throttled functions which trigger both on the leading
and trailing edge. This was then also ported to `ThrottledFunc` for
`DispatcherQueue`s and used for title/taskbar updates.
Closes#19188
## Validation Steps Performed
* In CMD run:
```batch
FOR /L %N IN () DO @echo %time%
```
* Doesn't hang the UI ✅
This PR resolves an issue where scrollbar marks created by shell
integration sequences (OSC 133 FTCS, OSC 1337 iTerm2, and OSC 9;12
ConEmu sequences) were not visible on the scrollbar until the user
manually scrolled.
The problem was that while marks were being created in the buffer
correctly, the UI wasn't being notified to refresh the scrollbar
display. The fix adds a new NotifyShellIntegrationMark() method to the
ITerminalApi interface that calls _NotifyScrollEvent() to trigger
scrollbar refresh, and updates all shell integration sequence handlers
in AdaptDispatch to call this notification method after creating marks.
This ensures scrollbar marks appear immediately when shell integration
sequences are processed, bringing feature parity between auto-detected
and shell-integration-based marks.
Closes#19104
Most of `ColorHelper` was unused and one of them had UB.
Related to #19183
## Validation Steps Performed
* Set a custom tabRow theme color
Split button looks similar to before ✅
* White/black FG color decision for colored
tabs is similar to before ✅
This PR fixes issue #7130 where WT_SESSION and WT_PROFILE_ID environment
variables were being duplicated in the WSLENV environment variable when
multiple terminal sessions were created.
The previous implementation always appended WT_SESSION:WT_PROFILE_ID: to
WSLENV without checking if these variables already existed, causing
duplication.
Closes#7130
Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
The bulk of this work is changing `Command::Name` (and its descendants
like `GenerateName`) to support looking up names in English and in the
local language.
When matching a "palette item" with a "subtitle" (a new field introduced
to store the English command name when the current language is not
English), the weight of the subtitle is used only if it is greater than
the weight of the name. This ensures that we do not penalize or
over-promote results that contain similar Latin letters in both fields.
Refs #19130, #19131, #19132, #19165Closes#7039