I don't actually know why this is happening, because it doesn't
happen with startup actions specified in the settings file.
In any case, it's fixed with more delays.
Closes#18572
## Validation Steps Performed
* Create a tab with 2 panes
* Tear it off into a new window
* New window has 1 tab with 2 panes ✅
* `_ApplyLanguageSettingChange` calls `PrimaryLanguageOverride`
(the WinRT API function) and we would call it every time a new
window is created. Now it's only called on settings load.
* `_RegisterTabEvents` would listen for "Content" changes which can
be null. `IVector::Append` throws if a null object is given.
In our case, it's null if the content got erased with nothing.
Additionally, this fixes a bug where we wouldn't call
`_ProcessLazySettingsChanges` on startup. This is important if the
settings file was changed while Windows Terminal wasn't running.
Lastly, there's a lifetime fix in this PR, which is a one-line change
and I didn't want to make a separate PR for that.
This is a theoretical fix for #18584 as I cannot reproduce the issue
anymore. It did happen briefly on one of my devices though, and at the
time I observed that it would persist a window with no startup actions.
This PR allows users to enable the tab bar in fullscreen mode.
A new setting; "showTabsFullscreen"; has been added which accepts a
boolean value. When `true`, then the tab bar will remain visible when
the terminal app is fullscreen. If the value is `false` (default), then
the tab bar is hidden in fullscreen.
When the tab bar is visible in fullscreen, the min/max/close controls
are hidden to maintain the expected behaviour of a fullscreen app.
## Validation Steps Performed
All unit tests are passing.
Manually verified that when the "launchMode" setting is "fullscreen" and
the "showTabsFullscreen" setting is `true`, the tab bar is visible on
launch.
Manually verified that changing the setting at runtime causes the tab
bar to be shown/hidden immediately (if the terminal is currently
fullscreen).
Manually verified that the new "showTabsFullscreen" setting is honoured
regardless of whether "showTabsInTitlebar" is set to `true` or `false`.
Closes#11130
As before, a minor refactor:
* I started off by removing the Monarch/Peasant with the goal of moving
it into and deduplicating its functionality with `WindowEmperor`.
* Since I needed a replacement for the Monarch (= ensures that there's
a single instance), I wrote single-instance code with a NT mutex
and by yeeting data across processes with `WM_COPYDATA`.
* This resulted in severe threading issues, because it now started up
way faster. The more I tried to solve them the deeper I had to dig,
because you can't just put a mutex around `CascadiaSettings`.
I then tried to seeif WinUI can run multiple windows on a single
thread and, as it turns out, it can.
So, I removed the multi- from the window threading.
* At this point I had dig about 1 mile deep and brought no ladder.
So, to finish it up, I had to clean up the entire eventing system
around `WindowEmperor`, cleaned up all the coroutines,
and cleaned up all the callbacks.
Closes#16183Closes#16221Closes#16487Closes#16532Closes#16733Closes#16755Closes#17015Closes#17360Closes#17420Closes#17457Closes#17799Closes#17976Closes#18057Closes#18084Closes#18169Closes#18176Closes#18191
## Validation Steps Performed
* It does not crash ✅
* New/close tab ✅
* New/close window ✅
* Move tabs between windows ✅
* Split tab into new window ✅
* Persist windows on exit / restore startup ✅
## Summary of the Pull Request
This extends the copy command to be able to include control sequences,
for use in tools that subsequently know how to parse and display that.
## References and Relevant Issues
https://github.com/microsoft/terminal/issues/15703
## Detailed Description of the Pull Request / Additional comments
At a high level, this:
- Expands the `CopyTextArgs` to have a `withControlSequences` bool.
- Plumbs that bool down through many layers to where we actuall get
data out of the text buffer.
- Modifies the existing `TextBuffer::Serialize` to be more generic
and renames it to `TextBuffer::ChunkedSerialize`.
- Uses the new `ChunkedSerialize` to generate the data for the copy
request.
## Validation Steps Performed
To test this I've manually:
- Generated some styled terminal contents, copied it with the control
sequences, pasted it into a file, `cat`ed the file and seen that it
looks the same.
- Set `"firstWindowPreference": "persistedWindowLayout"` and
validated that the contents of windows are saved and
restored with styling intact.
I also checked that `Invoke-OpenConsoleTests` passed.
## PR Checklist
- [x] Closes#15703
- [ ] 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/756
- [x] Schema updated (if necessary)
I sure hope I didn't break anything!
While `til::math` was a good idea its convenience led us to use it
in the only place where it absolutely must not be used: The UI code.
So, this PR replaces all those `til::point`s, etc., with floats.
Now we use DIPs consistently throughout all layers of the UI code,
except for the UIA area (that would've required too many changes).
## Validation Steps Performed
Launch, looks good, no obvious defects, UIA positioning seems ok. ✅
This adds support to the Terminal for parsing Markdown to XAML. We're
using https://github.com/github/cmark-gfm as our parser, so that we can
support the fullness of github-flavored markdown.
The parser parses the markdown to produce a `RichTextBlock`, which
covers just about all the scenarios we need. Since we're initially just
targeting using this for "Release notes", I didn't implement
_everything_ in markdown[^1]. But headers, bold & italic, unordered
lists, images, links, code spans & blocks - all that works. We can work
on additional elements as we need them. The parser is encapsulated into
`Microsoft.Terminal.UI.Markdown.dll`, so that we won't load it on
startup, only when the pane is actually made the first time.
To test this out, I've added a `MarkdownPaneContent` pane type on
`x-markdown` (the `x-` is "experimental"). Go ahead and add that with:
```json
{ "command": { "action": "splitPane", "type": "x-markdown" } }
```
That's got the ability to load arbitrary MD files and render them. I
wouldn't call that experience finished though[^2][^3](and it probably
won't be in 1.22 timeframe). However, it is an excellent testbed for
validating what we do and do not support.
We'll use the markdown parser Soon<sup>TM</sup> for the What's New
panes.
* Done in pursuit of displaying release notes in the Terminal.
* Doesn't quite close out #16495
* Should make #8647 possible
* may help with #16484
[^1]: the most notable gap being "block quotes" with `>`. I don't think
I can draw a vertical line in a rich text block easily. Footnotes are
also missing, as well as tables.
[^2]: I say it's not finished because the aforementioned MD gaps. Also
the UX there is not polished at all.
[^3]: I don't believe we'll have time to polish out the pure markdown
pane for 1.22, but what the parser covers now is more than enough for
the release notes pane in time for 1.22
## Summary of the Pull Request
This PR is to allow users to set a custom icon for entries in the new tab menu for "action" and "profile" type entries.
## References and Relevant Issues
This PR is in response to #18103
## Detailed Description of the Pull Request / Additional comments
It is now possible to specify an optional "icon" setting for any "action" or "profile" type entry in the "newTabMenu" JSON settings. When specified, this icon will be used as the menu icon for that action/profile in the new tab menu. If not specified, the action/profile definition's default icon will be used instead (if present).
The Cascadia settings schema ("doc/cascadia/profiles.schema.json") has been updated to reflect this.
## Validation Steps Performed
Manually tested with multiple combinations of icon settings:
- ActionEntry:
- valid path in action definition and new tab entry (renders new tab entry icon)
- valid path in action definition but no path in new tab entry (renders action definition icon)
- no path in action definition, valid path in new tab entry (renders new tab entry icon)
- invalid path in action definition, valid path in new tab entry (renders new tab entry icon)
- valid path in action definition, invalid path in new tab entry (renders no icon)
- invalid path in both (renders no icon)
- no path in both (renders no icon)
- ProfileEntry:
- valid path in new tab entry (renders new tab entry icon)
- no path in new tab entry (renders profile's default icon)
- invalid path in new tab entry (renders no icon)
## PR Checklist
- [x] Closes#18103
- [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: [#808](https://github.com/MicrosoftDocs/terminal/pull/808)
- [x] Schema updated (if necessary)
`ResizeWindow` event in `TerminalApi` is handled and bubbled to
`TerminalApi->ControlCore->TermControl->TerminalPage->AppHost`. Resizing
is accepted only if the window is not in fullscreen or quake mode, and
has 1 tab and pane.
Relevant issues: #5094
This PR clones `winrt::fire_and_forget` and replaces the uncaught
exception handler with one that logs instead of terminating.
My hope is that this removes one source of random crashes.
## Validation Steps Performed
I added a `THROW_HR` to `TermControl::UpdateControlSettings`
before and after the suspension point and ensured the application
won't crash anymore.
## Summary of the Pull Request
Improves Quick Fix's suggestions to use WinGet API and actually query
winget for packages based on the missing command.
To interact with the WinGet API, we need the
`Microsoft.WindowsPackageManager.ComInterop` NuGet package.
`Microsoft.WindowsPackageManager.ComInterop.Additional.targets` is used
to copy over the winmd into CascadiaPackage. The build variable
`TerminalWinGetInterop` is used to import the package properly.
`WindowsPackageManagerFactory` is used as a centralized way to generate
the winget objects. Long-term, we may need to do manual activation for
elevated sessions, which this class can easily be extended to support.
In the meantime, we'll just use the normal `winrt::create_instance` on
all sessions.
In `TerminalPage`, we conduct the search asynchronously when a missing
command was found. Search results are limited to 20 packages. We try to
retrieve packages with the following filters set, then fallback into the
next step:
1. `PackageMatchField::Command`,
`PackageFieldMatchOption::StartsWithCaseInsensitive`
2. `PackageMatchField::Name`,
`PackageFieldMatchOption::ContainsCaseInsensitive`
3. `PackageMatchField::Moniker`,
`PackageFieldMatchOption::ContainsCaseInsensitive`
This aligns with the Microsoft.WinGet.CommandNotFound PowerShell module
([link to relevant
code](9bc83617b9/src/WinGetCommandNotFoundFeedbackPredictor.cs (L165-L202))).
Closes#17378Closes#17631
Support for elevated sessions tracked in #17677
## References
-
https://github.com/microsoft/winget-cli/blob/master/src/Microsoft.Management.Deployment/PackageManager.idl:
winget object documentation
## Validation Steps Performed
- [X] unelevated sessions --> winget query performed and presented
- [X] elevated sessions --> nothing happens (got rid of `winget install
{}` suggestion)
Between fmt 7.1.3 and 11.0.2 a lot has happened. `wchar_t` support is
now more limited and implicit conversions don't work anymore.
Furthermore, even the non-`FMT_COMPILE` API is now compile-time checked
and so it fails to work in our UI code which passes `hstring` format
strings which aren't implicitly convertible to the expected type.
`fmt::runtime` was introduced for this but it also fails to work for
`hstring` parameters. To solve this, a new `RS_fmt` macro was added
to abstract the added `std::wstring_view` casting away.
Finally, some additional changes to reduce `stringstream` usage
have been made, whenever `format_to`, etc., is available.
This mostly affects `ActionArgs.cpp`.
Closes#16000
## Validation Steps Performed
* Compiles ✅
* Settings page opens ✅
Turns out, when the branding disables the feature, we try to get
`QuickFixMenu` when it's not loaded, causing a crash in TerminalPage.
Since we end up loading the quick fix menu when we scroll or apply UI
settings, we're actually loading the quick fix menu pretty early on. So
might as well remove the `x:Load="False"`. If we feel strongly about
keeping the lazy loading functionality, we can do that later (and
probably apply the same heuristic to the other XAML we're registering in
TerminalApp).
This also adds a feature flag check when registering the menu in
TerminalApp.
Closes#17548
In the spec review, we agreed these didn't really need to be saved to
the user's own settings file. This removes parsing and saving for the
`experimental.saveSnippet` action, but we still have the action
_internally_. This is powered by a new x-macro for "INTERNAL_" actions.
Follow-up from #16513.
As discussed in the bug bash. It should be closable with a button.
This also changes the tab color to match the Settings tabs.
This also fixes a crash where dragging just a snippets pane out to it's
own window would crash.
This adds a snippets pane, which can be a static pane with all your
snippets (`sendInput` actions) in it. (See #17329)
This pane has a treeview with these actions in it, that we can filter
with a textbox at the top.
Play buttons next to entries make it quick to run the command you found.
Bound in the default actions with
```json
{ "command": { "action": "splitPane", "type": "snippets" }, "id": "Terminal.OpenSnippetsPane", "name": { "key": "SnippetsPaneCommandName" } },
```
re: #1595
----
TODO, from 06-04 bug bash
* [x] Snippets pane doesn't display some "no snippets found" text if
there aren't any yet
* [x] open snippets pane; find a "send input"; click the play button on
it; input is sent to active pane; begin typing
* [x] I can open an infinite amount of suggestions panes
* ~I'm closing this as by-design for now at least. Nothing stopping
anyone from opening infinite of any kind of pane.~
* ~This would require kind of a lot of refactoring in this PR to mark a
kind of pane as being a singleton or singleton-per-tab~
* Okay everyone hates infinite suggestions panes, so I got rid of that
* [x] Ctrl+Shift+W should still work in the snippets pane even if focus
isn't in textbox
* [ ] open snippets pane; click on text box; press TAB key;
* [ ] If you press TAB again, I have no idea where focus went
* [x] some previews don't work. Like `^c` (`"input": "\u0003"`)
* [x] nested items just give you a bit of extra space for no reason and
it looks a little awkward
* [x] UI Suggestion: add padding on the right side
* [ ] [Accessibility] Narrator says "Clear buffer; Suggestions found
132" when you open the snippets pane
- Note: this is probably Narrator reading out the command palette (since
that's where I opened it from)
- We should probably expect something like "Snippets", then (assuming
focus is thrown into text box) "Type to filter snippets" or something
like that
### `OSC 9001; CmdNotFound; <missingCmd>`
Adds support for custom OSC "command not found" sequence `OSC 9001;
CmdNotFound; <missingCmd>`. Upon receiving the "CmdNotFound" variant
with the missing command payload, we send the missing command up to the
Quick Fix menu and add it in as `winget install <missingCmd>`.
### Quick Fix UI
The Quick Fix UI is a new UI surface that lives in the gutter (left
padding) of your terminal. The button appears if quick fixes are
available. When clicked, a list of suggestions appears in a flyout. If
there is not enough space in the gutter, the button will be presented in
a collapsed version that expands to a normal size upon hovering over it.
The Quick Fix UI was implemented similar to the context menu. The UI
itself lives in TermControl, but it can be populated by other layers
(i.e. TermApp layer).
Quick Fix suggestions are also automatically loaded into the Suggestions
UI.
If a quick fix is available and a screen reader is attached, we dispatch
an announcement that quick fixes are available to notify the user that
that's the case.
Spec: #17005#16599
### Follow-ups
- #17377: Add a key binding for quick fix
- #17378: Use winget to search for packages using `missingCmd`
---------
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
Co-authored-by: Dustin L. Howett <dustin@howett.net>
First, this adds `GraphemeTableGen` which
* parses `ucd.nounihan.grouped.xml`
* computes the cluster break property for each codepoint
* computes the East Asian Width property for each codepoint
* compresses everything into a 4-stage trie
* computes a LUT of cluster break rules between 2 codepoints
* and serializes everything to C++ tables and helper functions
Next, this adds `GraphemeTestTableGen` which
* parses `GraphemeBreakTest.txt`
* splits each test into graphemes and break opportunities
* and serializes everything to a C++ table for use as unit tests
`CodepointWidthDetector.cpp` was rewritten from scratch to
* use an iterator struct (`GraphemeState`) to maintain state
* accumulate codepoints until a break opportunity arises
* accumulate the total width of a grapheme
* support 3 different measurement modes: Grapheme clusters,
`wcswidth`-style, and a mode identical to the old conhost
With this in place the following changes were made:
* `ROW::WriteHelper::_replaceTextUnicode` now uses the new
grapheme cluster text iterators
* The same function was modified to join new text with existing
contents of the current cell if they join to form a cluster
* Otherwise, a ton of places were modified to funnel the selection
of the measurement mode over from WT's settings to ConPTY
This is part of #1472
## Validation Steps Performed
* So many tests ✅
* https://github.com/apparebit/demicode works fantastic ✅
* UTF8-torture-test.txt works fantastic ✅
With the move to Action IDs, it doesn't quite make sense anymore for a
`Command` to know which keys map to it. This PR removes all `Keys` from
`Command`, and any callers to that now instead query the `ActionMap` for
that Command's keys.
Closes#17160Closes#13943
As outlined in #16816, refactor `ActionMap` to use the new action IDs
added in #16904
## Validation steps performed
- [x] Legacy style commands are parsed correctly (and rewritten to the
new format)
- [x] Actions are still layered correctly and their IDs can be used to
'overwrite' actions in earlier layers
- [x] Keybindings that refer to an ID defined in another layer work
correctly
- [x] User-defined actions without an ID have one generated for them
(and their settings file is edited with it)
- [x] Schema updated
Refs #16816Closes#17133
I noticed this while working on #17330. We're constructing a whole
lambda just to do this wacky weak_ref logic, and that feels... gross. We
should just make this a bound method and a typed event, so we can just
use the one event handler regardless
Calling Close() from within WalkPanes is not safe. Simply using
_FindPane is enough to fix this.
This PR also fixes another potential source of infinite recursion, and
fixes panes being passed by-value into the callbacks.
Closes#17305
## Validation Steps Performed
* Split panes vertically 3 times
* `exit` the middle, the bottom and final one, in that order
* Doesn't crash ✅
First, this makes use of `PSEUDOCONSOLE_INHERIT_CURSOR` to stop ConPTY
from emitting a CSI 2 J on startup. Then, it uses
`Terminal::SetViewportPosition` to fake-scroll the viewport down so that
only 3 lines of scrollback are visible. It avoids printing actual
newlines because if we later change the text buffer to actually track
the written contents, we don't want those newlines to end up in the next
buffer snapshot.
Closes#17274
## Validation Steps Performed
* Restore cmd multiple times
* There's always exactly 3 lines visible ✅
As it turns out, for handoff'd connections `Initialize` isn't called
and this meant the `_sessionId` was always null.
After this PR we still don't have a `_profileGuid` but that's probably
not a critical issue, since that's an inherent flaw with handoff.
It can only be solved in a robust manner if WT gets launched before the
console app is launched, but it's unlikely for that to ever happen.
## Validation Steps Performed
* Launch
* Register that version of WT as the default
* Close all tabs (Ctrl+Shift+W)
* `persistedWindowLayouts` is empty ✅
* Launch cmd/pwsh via handoff
* You get 1 window ✅
* Close the window (= press the X button)
* Launch
* You get 2 windows ✅
While `double` is probably generally preferable for UI code,
our application is essentially a complex wrapper wrapper around
DWrite, D2D and D3D, all of which use `float` exclusively.
Of course it also uses XAML, but that one uses `float` for roughly
1/3rd of its API functions, so I'm not sure what it prefers.
Additionally, it's mostly a coincidence that we use WinUI/XAML for
Windows Terminal whereas DWrite/D2D/D3D are effectively essential.
This is demonstrated by the fact that we have a `HwndTerminal`,
while there's no alternative to e.g. D3D on Windows.
The goal of this PR is that DIP based calculations never end up
mixing `float` and `double`. This PR also changes opacity-related
values to `float` because I felt like that fits the theme.
In the spirit of #15360 this implements the copy part.
The problem is that we have an issue accessing the clipboard while
other applications continue to work just fine. The major difference
between us and the others is that we use the WinRT clipboard APIs.
So, the idea is that we just use the Win32 APIs instead.
The feel-good side-effect is that this is (no joke) 200-1000x faster,
but I suspect no one will notice the -3ms difference down to <0.01ms.
The objective effect however is that it just works.
This may resolve#16982.
## Validation Steps Performed
* Cycle through Text/HTML/RTF-only in the Interaction settings
* Paste the contents into Word each time
* Text is plain and HTML/RTF are colored ✅
This changes `NewTabArgs`, `SplitPaneArgs`, and `NewWindowArgs` to
accept a `INewContentArgs`, rather than just a `NewTerminalArgs`. This
allows a couple things:
* Users can open arbitrary types of panes with the existing `splitPane`,
`newWindow` actions, just by passing `"type": "scartchpad"` (for
example). This is a lot more flexible than re-defining different
`"openScratchpad"`, `"openTasksPane"`, etc, etc actions for every kind
of pane.
* This allows us to use the existing machinery of session restore to
also restore non-terminal panes.
The `type` property was added to `newTab`, `splitPane`, `newWindow`.
When omitted, we still just treat the json as a blob of NewTerminalArgs.
There's not actually any other kinds of `INewContentArgs` in this PR
(other than the placeholder `GenericContentArgs`). In
[`dev/migrie/fhl/md-pane`](https://github.com/microsoft/terminal/compare/dev/migrie/f/tasks-pane...dev/migrie/fhl/md-pane),
I have a type of pane that would LOVE to add some args here. So that's
forward-thinking.
There's really just two stealth types of pane for now: `settings`, and
`scratchpad`. Those I DON'T have as constants or anything in this PR.
They probably should be? Though, I suspect around the time of the tasks
& MD panes, I'll come up with whatever structure I actually want them to
take.
### future considerations here
* In the future, this should allow extensions to say "I know how to host
`foo` content", for 3p content.
* The `wt` CLI args were not yet updated to also accept `--type` yet.
There's no reason we couldn't easily do that.
* I considered adding `ICanHasCommandline` to allow arbitrary content to
generate a `wt` commandline-serializable string. Punted on that for now.
## other PRs
* #16170
* #16171
* #16172
* #16895
* #16914 <-- you are here
Closes#17014
As @lhecker noted in the #16172 review, `UpdateTerminalSettings` is
wacky. We can just pass the cache in at the start, then reset it and
reuse it in `UpdateSettings`. One fewer `try_as`!
... technically. We still won't let it actually _be_ a pane, but now it
acts like one. It's hosted in a `SettingsPaneContent`. There's no more
`SettingsTab`. It totally _can_ be in a pane (but don't?)
## Validation Steps Performed
* Still opens the settings
* Only opens a single settings tab, or re-activates the existing one
* Session restores!
* Updates the title of the tab appropriately
* I previously _did_ use the scratchpad action to open the settings in a
pane, and that worked.
## Related PRs
* #16170
* #16171
* #16172 <-- you are here
* #16895
Refs #997Closes#8452
This changeset allows Windows Terminal to dump its buffer contents as
UTF-16LE VT text onto disk and restore it later. This functionality is
enabled whenever `persistedWindowLayout` is being used.
Closes#961Closes#16741
## Validation Steps Performed
* Open multiple windows with multiple tabs and restart the app
Everything's restored ✅
* Reopen a tab with output from `RenderingTests.exe`
Everything's restored ✅
* Closing tabs and windows with Ctrl+W deletes their buffer dumps ✅
* Closing tabs doesn't create buffer dumps ✅
This removes `VtApiRoutines` and the VT passthrough mode.
Why? While VT passthrough mode has a clear advantage (doesn't corrupt
VT sequences) it fails to address other pain points (performance,
out-of-sync issues after resize, etc.). Alternative options are
available which have less restrictions.
Why now? It's spring! Spring cleanup!
Instead of `Pane` hosting a `TermControl` directly, it now hosts an
`IPaneContent`. This is an abstraction between the TermControl and the
pane itself, to allow for arbitrary implementations of `IPaneContent`,
with things that might not be terminals.
## References and Relevant Issues
* #997
* #1000
## Detailed Description of the Pull Request / Additional comments
This PR by itself doesn't do much. It's just a refactoring.
- It doesn't actually add any other types of pane content.
- It overall just tries to move code whenever possible, with as little
refactoring as possible. There are some patterns from before that don't
super scale well to other types of pane content (think: the `xyzChanged`
events on `IPaneContent`).
- There's a few remaining places where Pane is explicitly checking if
its content is a terminal. We probably shouldn't, but meh
There are two follow-up PRs to this PR:
* #16171
* #16172
In addition, there's more work to be done after these merge:
* TODO! issue number for "Replace `IPaneContent::xyzChanged` with
`PropertyChanged` events"
* TODO! issue number for "Re-write state restoration so panes don't
produce `NewTerminalArgs`"
## Validation Steps Performed
* It still launches
* It still works
* Broadcasting still works
* The weird restart connection thing from #16001 still works
## PR Checklist
- [x] Closes#997
## other PRs
* #16170 <-- you are here
* #16171
* #16172
**Default Terminal**: Everyone who cares to know, knows. Everyone who
doesn't, has an annoying bar above all terminals
I had to introduce a workaround for the fact that unknown dismissed
message keys in `state.json` result in Terminal exploding on launch.
😁 That's tracked in #16874.
Closes#11930 (but not in the way you'd expect)
This PR automagically finds and replaces all[^1] usages of our
TYPED_EVENT macro with `til::event`. Benefits include:
* less macro magic
* editors are more easily able to figure out the relationship between
`til::event<> Foo;`, `Foo.raise(...)`, and `bar.Foo({this,
&Bar::FooHandler})` (whereas before the relationship between
`_FooHandlers(...)` and `bar.Foo({...})`) couldn't be figured out by
vscode & sublime.
Other find & replace work that had to be done:
* I added the `til::typed_event<>` == `<IInspectable, IInspectable>`
thing from #16170, since that is goodness
* I actually fixed `til::property_changed_event`, so you can use that
for your property changed events. They're all the same anyways.
* events had to come before `WINRT_PROPERTY`s, since the latter macro
leaves us in a `private:` block
* `Pane::SetupChildCloseHandlers` I had to swap _back_, because the
script thought that was an event 🤦
* `ProfileViewModel::DeleteProfile` had to be renamed
`DeleteProfileRequested`, since there was already a `DeleteProfile`
method on it.
* WindowManager.cpp was directly wiring up it's `winrt::event`s to the
monarch & peasant. That doesn't work with `til::event`s and I'm kinda
surprised it ever did
<details>
<summary>The script in question</summary>
```py
import os
import re
def replace_in_file(file_path, file_name):
with open(file_path, 'r', encoding="utf8") as file:
content = file.read()
found_matches = False
# Define the pattern for matching
pattern = r' WINRT_CALLBACK\((\w+),\s*(.*?)\);'
event_matches = re.findall(pattern, content)
if event_matches:
found_matches = True
print(f'found events in {file_path}:')
for match in event_matches:
name = match[0]
args = match[1]
if name == "newConnection" and file_name == "ConptyConnection.cpp":
# This one is special
continue
old_declaration = 'WINRT_CALLBACK(' + name + ', ' + args + ');'
new_declaration = 'til::event<' + args + '> ' + name + ';' if name != "PropertyChanged" else 'til::property_changed_event PropertyChanged;'
print(f' {old_declaration} -> {new_declaration}')
content = content.replace(old_declaration, new_declaration)
typed_event_pattern = r' TYPED_EVENT\((\w+),\s*(.*?)\);'
typed_matches = re.findall(typed_event_pattern, content)
if typed_matches:
found_matches = True
print(f'found typed_events in {file_path}:')
for match in typed_matches:
name = match[0]
args = match[1]
if name == "newConnection" and file_name == "ConptyConnection.cpp":
# This one is special
continue
old_declaration = f'TYPED_EVENT({name}, {args});'
was_inspectable = (args == "winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable" ) or (args == "IInspectable, IInspectable" )
new_declaration = f'til::typed_event<{args}> {name};' if not was_inspectable else f"til::typed_event<> {name};"
print(f' {old_declaration} -> {new_declaration}')
content = content.replace(old_declaration, new_declaration)
handlers_pattern = r'_(\w+)Handlers\('
handler_matches = re.findall(handlers_pattern, content)
if handler_matches:
found_matches = True
print(f'found handlers in {file_path}:')
for match in handler_matches:
name = match
if name == "newConnection" and file_name == "ConptyConnection.cpp":
# This one is special
continue
old_declaration = f'_{name}Handlers('
new_declaration = f'{name}.raise('
print(f' {old_declaration} -> {new_declaration}')
content = content.replace(old_declaration, new_declaration)
if found_matches:
with open(file_path, 'w', encoding="utf8") as file:
file.write(content)
def find_and_replace(directory):
for root, dirs, files in os.walk(directory):
if 'Generated Files' in dirs:
dirs.remove('Generated Files') # Exclude the "Generated Files" directory
for file in files:
if file.endswith('.cpp') or file.endswith('.h') or file.endswith('.hpp'):
file_path = os.path.join(root, file)
try:
replace_in_file(file_path, file)
except Exception as e:
print(f"error reading {file_path}")
if file == "TermControl.cpp":
print(e)
# raise e
# Replace in files within a specific directory
directory_path = 'D:\\dev\\public\\terminal\\src'
find_and_replace(directory_path)
```
</details>
[^1]: there are other macros we use that were also using this macro,
those weren't replaced.
---------
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
This pull request introduces the module Microsoft.Terminal.UI.dll, and
moves into it the following things:
- Any `IDirectKeyListener`
- All XAML converter helpers from around the project
- ... including `IconPathConverter` from TerminalSettingsModel
- ... but not `EmptyStringVisibilityConverter`, which has died
It also adds a XAML Markup Extension named `mtu:ResourceString`, which
will allow us to refer to string resources directly from XAML. It will
allow us to remove all of the places in the code where we manually set
resources on XAML controls.
---------
Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
Basically, title. If you null out the icon, we'll automatically try to
use the `commandline` as an icon (because we can now). We'll even be
smart about it - `cmd.exe /k echo wassup` will still just use the ico of
`cmd.exe`.
This doesn't work for `ubuntu.exe` (et. al), because that commandline is
technically a reparse point, that doesn't actually have an icon
associated with it.
Closes#705
`"none"` becomes our sentinel value for "no icon".
This will also use the same `NormalizeCommandLine` we use for
commandline matching for finding the full path to the exe.
This contains all the parts of #16598 that aren't specific to session
restore, but are required for the code in #16598:
* Adds new GUID<>String functions that remove the `{}` brackets.
* Adds `SessionId` to the `ITerminalConnection` interface.
* Flush the `ApplicationState` before we terminate the process.
* Not monitoring `state.json` for changes is important as it prevents
disturbing the session state while session persistence is ongoing.
That's because when `ApplicationState` flushes to disk, the FS
monitor will be triggered and reload the `ApplicationState` again.
TIL: You could Ctrl+V files into Windows Terminal and here I am,
always opening the context menu and selecting "Copy as path"... smh
This restores the support by adding a very rudimentary HDROP handler.
The flip side of the regression is that I learned about this and so
conhost also gets this now, because why not!
Closes#16627
## Validation Steps Performed
* Single files can be pasted in WT and conhost ✅
Avoid generating extra formatted copies when action's `copyFormatting`
is not present and globally set `copyFormatting` is used.
Previously, when the action's `copyFormatting` wasn't set we deferred
the decision of which formats needed to be copied to the
`TerminalPage::CopyToClipboard` handler. This meant we needed to copy
the text in all the available formats and pass it to the handler to copy
the required formats after querying the global `copyFormatting`.
To avoid making extra copies, we'll store the global `copyFormatting` in
TerminalSettings and pass it down to `TermControl`. If
`ControlCore::CopySelectionToClipboard()` doesn't receive action
specific `copyFormatting`, it will fall back to the global one _before
generating the texts_.
## Validation Steps Performed
- no `copyFormatting` set for the copy action: Copies formats according
to the global `copyFormatting`.
- `copyFormatting` is set for the copy action: Copies formats according
to the action's `copyFormatting`.
`GetAt` can throw if the index is out of range. We don't check that in
some places. This fixes some of those.
I don't think this will take care of #15689, but it might help?
Updated the function `TerminalPage::CloseWindow` to include logic for
closing context and flyout menus so that they are dismissed before the
warning is displayed.
Closes#16039
The Win32 API is significantly faster than the WinRT one, in the order
of around 300-1000x depending on the CPU and CPU load.
This might slightly improve the situation around #15315, but I suspect
that it requires many more fixes. For instance, we don't really have a
single text input "queue" into which we write. Multiple routines that
`resume_background` just to `WriteFile` into the input pipe are thus
racing against each other, contributing to the laggy feeling.
I also fear that the modern Windows text stack might be inherently
RPC based too, producing worse lag with rising CPU load.
This might fix#14323
## Validation Steps Performed
* Paste text from Edge ✅
* Paste text from Notepad ✅
* Right click the address bar in Explorer, choose "Copy address",
paste text into WT ✅
---------
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
As mentioned in #15760
> > When you right-click on a non-active pane, it becomes active, but the context menu may be displayed before this happens, thus showing the Restart Connection item based the wrong pane's status.
>
> As far as I can see, when a pane is (right)clicked:
>
> 1. If unfocused, `Focus` is called. This goes through the `GotFocus` handler which eventually calls `tab->_UpdateActivePane(sender);`
> 2. `PointerPressed` is raised which eventually shows the context menu
>
> The first point is done asynchronously, so may update the active pane too late when the menu is already displayed (despite both end up in the UI thread).
To fix this: we plumb the control that the context menu was opened for all the way through to where the event is actually handled (in `_PopulateContextMenu`)
* [x] Tested manually
Co-authored-by: Marco Pelagatti <1140981+mpela81@users.noreply.github.com>
I noticed this last week, but forgot to file. If you have a pair of
splits, and `exit -1` the first, you can't use `enter` to restart it.
This PR fixes that. Basically, `TerminalPage` registers it's
`_restartPaneConnection` handler when it makes a new `Pane` object. It
registers the callback straight to the `Pane`. However, when a `Pane`
gets split, it makes a _new_ `Pane` object, and moves the original
content into the new pane. `TerminalPage` however, would never hook up
its own callback to that newly created pane.
This fixes that.