I was talking with @plante-msft this week at Build and we agreed that
.75 is just a bit too chatty. .8 seems like it's a better threshold -
sure, it'll miss a few of the harder edge cases, but it'll chime in less
frequently when it's just wrong.
## Summary of the Pull Request
The dirty view calculation in the `XtermEngine::StartPaint` method was
originally used to detect a full frame paint that would require a clear
screen, but that code was removed as part of PR #4741, making this
calculation obsolete.
The `performedSoftWrap` variable in the `XtermEngine::_MoveCursor`
method was assumedly a remanent of some WIP code that was mistakenly
committed in PR #5181. The variable was never actually used.
## Validation Steps Performed
All the unit tests still pass and nothing seems obviously broken in
manual testing.
## PR Checklist
- [x] Closes#17280
This PR adds support for multiples pages in the VT architecture, along
with new operations for moving between those pages: `NP` (Next Page),
`PP` (Preceding Page), `PPA` (Page Position Absolute), `PPR` (Page
Position Relative), and `PPB` (Page Position Back).
There's also a new mode, `DECPCCM` (Page Cursor Coupling Mode), which
determines whether or not the active page is also the visible page, and
a new query sequence, `DECRQDE` (Request Displayed Extent), which can be
used to query the visible page.
## References and Relevant Issues
When combined with `DECCRA` (Copy Rectangular Area), which can copy
between pages, you can layer content on top of existing output, and
still restore the original data afterwards. So this could serve as an
alternative solution to #10810.
## Detailed Description of the Pull Request / Additional comments
On the original DEC terminals that supported paging, you couldn't have
both paging and scrollback at the same time - only the one or the other.
But modern terminals typically allow both, so we support that too.
The way it works, the currently visible page will be attached to the
scrollback, and any content that scrolls off the top will thus be saved.
But the background pages will not have scrollback, so their content is
lost if it scrolls off the top.
And when the screen is resized, only the visible page will be reflowed.
Background pages are not affected by a resize until they become active.
At that point they just receive the traditional style of resize, where
the content is clipped or padded to match the new dimensions.
I'm not sure this is the best way to handle resizing, but we can always
consider other approaches once people have had a chance to try it out.
## Validation Steps Performed
I've added some unit tests covering the new operations, and also done a
lot of manual testing.
Closes#13892
Tests added/passed
This implements builtin glyphs for our Direct2D renderer, as well as
dashed and curly underlines. With this in place the only two features
it doesn't support are inverted cursors and VT soft fonts.
This allows us to remove the `_hack*` members introduced in a6a0e44.
The implementation of dashed underlines is trivial, while curly
underlines use quadratic bezier curves. Caching the curve as a sprite
is possible, however I feel like that can be done in the future.
Builtin glyphs on the other hand require a cache, because otherwise
filling the entire viewport with shaded glyphs would result in poor
performance. This is why it's built on top of `ID2D1SpriteBatch`.
Unfortunately the API causes an eager flush of other pending graphics
instructions, which is why there's still a decent perf hit.
Finally, as a little extra, this fixes the rounded powerline glyph
shapes being slightly cut off. The fix is to simply don't round the
position and radius of the ellipsis/semi-circle.
Closes#17224
## Validation Steps Performed
* RenderingTests.exe updated ✅
* All supported builtin glyphs look sorta right at different sizes ✅
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 ✅
This clamps the font sizes between 1 and 100. Additionally, it fixes
a warning that I randomly noticed when reproducing the issue: D2D
complained that `EndDraw` must be called before releasing resources.
Finally, this fixes a crash when the terminal size is exactly (1,1)
cells, which happened because the initial (invalid) size was (1,1) too.
This doesn't fully fix all font-size related issues, but that's
currently difficult to achieve, as for instance the swap chain size
isn't actually based on the window size, nay, it's based on the cell
size multiplied by the cell count. So if the cell size is egregiously
large then we get a swap chain size that's larger than the display and
potentially larger than what the GPU supports which results in errors.
Closes#17227
A few minor changes to better guide people along new features in 1.21.
The font face box gets a sub-text that explains how to add multiple
fonts and the builtin glyph toggle now explains its dependence to D3D.
This is fallout from #16937.
* Typing a command then backspacing the chars then asking for
suggestions would think the current commandline ended with spaces,
making filtering very hard.
* The currently typed command would _also_ appear in the command
history, which isn't useful.
I actually did TDD for this and wrote the test first, then confirmed
again running through the build script, I wasn't hitting any of the
earlier issues.
Closes#17241Closes#17243
We need to lock the buffer when getting the viewport/cursor position.
This caused the UIA overlay to randomly fail to update.
## Validation Steps Performed
* Open a cmd tab and hold any key immediately
* Repeat until you're somewhat confident it's gone ✅
## Validation Steps Performed
- Opened multi-tab terminal window with Narrator. Narrator can read
characters from the tabs.
- Started a drag and drop (tear-off) of a tab, and it didn't crash. This
was repeated multiple times.
This centralized all our ESRP calls in one file, which will make it
easier in the future when we are invariable required to change how we
call it again.
## Summary of the Pull Request
When the renderer calculates the invalidate region for the cursor, it
needs to take the line rendition into account. But it was using a
relative coordinate rather than absolute coordinate when looking up the
line rendition for the row, so the calculated region could easily be
incorrect.
With this PR we now use the line rendition that was already being cached
in the `CursorOptions` structure, so we avoid needing to look it up
anyway. Similarly I've replaced the `IsCursorDoubleWidth` lookup with
the value that was already cached in the `CursorOptions` structure.
## Validation Steps Performed
I've confirmed that the test case in issue #17226 is now working as
expected.
## PR Checklist
- [x] Closes#17226
When the VT render engine checks whether the cursor has moved in the
`InvalidateCursor` method, it does so by comparing the origin of the
given cursor region with the last text output coordinates. But these two
values are actually from different coordinate systems, and when on a
double-width line, the x text coordinate is half of the corresponding
screen coordinate. As a result, the movement detection is sometimes
incorrect.
This PR fixes the issue by adding another field to track the last cursor
origin in screen coordinates, so we have a meaningful value to compare
against.
## References and Relevant Issues
The previous cursor movement detection was added in PR #17194 to fix
issue #17117.
## Validation Steps Performed
I've confirmed that the test case from issue #17232 is now fixed, and
the test case from issue #17117 is still working as expected.
## PR Checklist
- [x] Closes#17232
Fix Terminal crashing when experimental PowerShell menu completion is
very quickly invoked multiple times.
`Command::ParsePowerShellMenuComplete` can be called from multiple
threads, but it uses a `static` `Json::CharReader`, which cannot safely
parse data from multiple threads at the same time. Removing `static`
fixes the problem, since every function call gets its own `reader`.
Validation: Pressed Ctrl+Space quickly a few times with hardcoded huge
JSON as the completion payload. Also shown at the end of the second
video in #17220.
Closes#17220
On Windows 10 Emojis don't finish composition until the Emoji picker
panel is closed. Each emoji is thus its own composition range.
`firstRange` thus caused only the first emoji to finish composition.
The end result was that all remaining emojis would stay around
forever, with the user entirely unable to clear them.
## Validation Steps Performed
* Windows 10 VM
* Open Emoji picker (Win+.)
* Press and hold Enter on any Emoji
* Press Esc to finish the composition
* All of the Emoji can be backspaced / deleted
This fixes 2 bugs:
* `PersistState` being called when the window is closed
(as opposed to closing the tab). The settings check was missing.
* Session cleanup running depending on whether the feature is
currently enabled as opposed to whether it was enabled on launch.
Closes#17206Closes#17207
## Validation Steps Performed
* Create a bunch of leftover buffer_*.txt files by running
the current Dev version off of main
* Build this branch, then open and close a window
* All buffer_*.txt are gone and state.json is cleaned up ✅
We use `if (auto self = weakSelf.get())` in a lot of places.
That assigns the value to `self` and then checks if it's truthy.
Sometimes we need to add a "is (app) closing" check because XAML,
so we wrote something akin to `if (self = ...; !closing)`.
But that's wrong because the correct `if (foo)` is the same as
`if (void; foo)` and not `if (foo; void)` and that meant that
we didn't check for `self`'s truthiness anymore.
This issue became apparent now, because we added a new kind of
delayed callback invocation (which is a lot cheaper).
This made the lack of a `nullptr` check finally obvious.
When the `DCS` passthrough code was first implemented, it relied on the
`ActionPassThroughString` method flushing the given string immediately.
However, that has since stopped being the case, so `DCS` operations end
up being delayed until the entire sequence has been parsed.
This PR fixes the issue by introducing a `flush` parameter to force an
immediate flush on the `ActionPassThroughString` method, as well as the
`XtermEngine::WriteTerminalW` method that it calls.
## Validation Steps Performed
I've confirmed that the test case in issue #17111 now updates the color
table as soon as each color entry is parsed, instead of delaying the
updates until the end of the sequence.
Closes#17111
When the VT render engine starts a paint operation, it first checks to
see whether there is actually something to do, and if not it can end the
frame early. However, the result of that check was being ignored, which
could sometimes result in an unwanted `SGR` reset being written to the
conpty pipe.
This was particular concerning when passing through `DCS` sequences,
because an unexpected `SGR` in the middle of the `DCS` string would
cause it to abort early.
This PR addresses the problem by making sure the `VtEngine::StartPaint`
return value is appropriately handled in the `XtermEngine` class.
## Detailed Description of the Pull Request / Additional comments
To make this work, I also needed to correct the `_cursorMoved` flag,
because that is one of things that determines whether a paint is needed
or not, but it was being set in the `InvalidateCursor` method at the
start of ever frame, regardless of whether the cursor had actually
moved.
I also took this opportunity to get rid of the `_WillWriteSingleChar`
method and the `_quickReturn` flag, which have been mostly obsolete for
a long time now. The only place the flag was still used was to optimize
single char writes when line renditions are active. But that could more
easily be handled by testing the `_invalidMap` directly.
## Validation Steps Performed
I've confirmed that the test case in issue #17117 is no longer aborting
the `DCS` color table sequence early.
Closes#17117
This fixes:
* `HRESULT`s not being shown as unsigned hex
* `D2DERR_RECREATE_TARGET` not being handled
* 4 calls not checking their `HRESULT` return
Out of the 4 only `CreateCompatibleRenderTarget` will throw in
practice, however it throws `D2DERR_RECREATE_TARGET` which is common.
Without this error handling, AtlasEngine may crash.
## Validation Steps Performed
* Set Graphics API to Direct2D
* Use `DXGIAdapterRemovalSupportTest.exe` to trigger
`D2DERR_RECREATE_TARGET`
* No error message is shown ✅
* If the `D2DERR_RECREATE_TARGET` handling is removed, the application
never crashes due to `cursorRenderTarget` being `nullptr` ✅
There were multiple bugs:
* GDI engine only paints whatever has been invalidated.
This means we need to not just invalidate the old cursor rect
but also the new one, or else movements may not be visible.
* The composition should be drawn at the cursor position even if
the cursor is invisible, but inside the renderer viewport.
* Conceptually, scrolling the viewport moves the relative cursor
position even if the cursor is invisible.
* An invisible cursor is not the same as one that's outside the
viewport. It's more like a cursor that's not turned on.
To resolve the first issue we simply need to call `InvalidateCursor`
again. To do so, it was abstracted into `_invalidateCurrentCursor()`.
The next 2 issues are resolved by un-`optional`-izing `CursorOptions`.
After all, even an invisible or an out-of-bounds cursor still has a
coordinate and it may still be scrolled into view.
Instead, it has the new `inViewport` property as a replacement.
This allows for instance the IME composition code in the renderer
to use the cursor coordinate while the cursor is invisible.
The last issue is fixed by simply changing the `.isOn` logic.
Closes#17150
## Validation Steps Performed
* In conhost with the GDI renderer:
`printf "\e[2 q"; sleep 2; printf "\e[A"; sleep 2; printf "\e[B"`
Cursor moves up after 2s and then down again after 2s. ✅
* Hide the cursor (`"\e[?25l"`) and use a CJK IME.
Words can still be written and deleted correctly. ✅
* Turning the cursor back on (`"\e[?25h"`) works ✅
* Scrolling shows/hides the cursor ✅
It may be more accurate to say: "Fix _known_ remaining buffer
serialization bugs", but I'll try to be positive about my code.
Initially, the buffer is initialized with the default attributes,
but once it begins to scroll, newly scrolled in rows are initialized
with the current attributes. This means we need to set the current
attributes to those of the upcoming row before the row comes up.
This is related to #17074.
## Validation Steps Performed
* Persist and restore a buffer 10 times
* All previous "Restore" status messages look correct ✅
* The escape sequences in the buffer file look correct ✅
Initially the PR restored the original v1 conhost code for
`MatchAndCopyAlias` which fixed the linked issue.
Afterwards, I've taken the liberty to rewrite the code to use modern
constructs again, primarily `string_view`. Additionally, the v1 code
first counted the number of arguments and then iterated through it
again to assemble them. This new code does both things at once.
Closes#15736
## Validation Steps Performed
The unit tests have been extended to cover multiple consecutive
spaces. All tests pass.
Noticed all these while prepping for Build:
* Promotes the stabilized features out of `experimental.`
* fixes a bug where a nested command with a `name` would match to a
`renameWindow` action, instead of a command.
* Adds the tab theme icon style
* fixes a bug where `ScrollToMarkAction` wasn't in the list of possible
args, so they would incorrectly get flagged as `moveTab`
* outright adds `experimental.rightClickContextMenu` which was missing
(?)
Something something code changes, fixes issue. Events need throwing,
some events don't need throwing, some events need throttling to
not overwhelm the flurble function within the gumbies component.
This is all boilerplate and it works now.
Closes#17171Closes#17172
## Validation Steps Performed
* Resetting the font axis/feature expander keeps
the add new button flyout sorted ✅
* Changing a font axis/feature value updates the preview ✅
* After changing the font, features/axes can still be edited ✅
You'll never believe this. Clicking on the dropdown button on a ComboBox
doesn't set `e.Tapped = true`. It bubbles up, and lands in our `Pane`'s
`Border`'s tapped handler. And in there, we yeet focus to the first
content. We end up stealing focus from the combobox, and then the
combobox doesn't actually open its dropdown.
So yea we can just fix that. Easy enough.
Closes#17062
---------
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
These feature tests continue to plague us. Seems like the most likely
outcome nowadays is that the test fails to attach immediately, so we
don't even get to the retry loop.
Easy enough. Let's move the AttachConsole into the loop too.
Re-add some machinery to special case settings tabs. When we're going to
persist a tab that only has a single settings pane in it, we'll now
promote that to the first-class "openSettings" action. This will allow
our other code in TerminalPage to route multiple settings tabs all to
the same tab.
This of course doesn't stop you from opening multiple settings tabs with
`{ "command": {"action": "newTab", "type": "settings"} }` actions. If we
did that, then that would prevent someone from having a settings pane in
the first pane, and a terminal to the right.
Closes#17070
This required me to push a bunch more parameters through the build
pipeline, but it gave me the opportunity to define them as variables
that can be set at queue time.
Due to #16821 everything about #16104 broke. This PR rights the wrongs
by rewriting all the `Font`-based code to not use `Font` at all.
Instead we split the font spec once into font families, do a lot of
complex logic to split font axes/features into used and unused ones
and construct all the UI elements. So. much. boilerplate. code.
Closes#16943
## Validation Steps Performed
There are more edge cases than I can list here... Some ideas:
* Edit the settings.json with invalid axis/feature keys ✅
* ...out of range values ✅
* Settings UI reloads when the settings.json changes ✅
* Adding axes/features works ✅
* Removing axes/features works ✅
* Resetting axes/features works ✅
* Axes/features apply in the renderer when saving ✅
I think this subtly regressed in #16611. Jump to
90b8bb7c2d (diff-f9112caf8cb75e7a48a7b84987724d754181227385fbfcc2cc09a879b1f97c12L171-L223)
`Terminal::SelectNewRegion` is the only thing that uses the return value
from `Terminal::_ScrollToPoints`. Before that PR, `_ScrollToPoints` was
just a part of `SelectNewRegion`, and it moved the start & end coords by
the `_VisibleStartIndex`, not the `_scrollOffset`.
Kinda weird there weren't any _other_ tests for `SelectNewRegion`?
I also caught a second bug while I was here - If you had a line with an
exact wrap, and tried to select that like with selectOutput, we'd
explode.
Closes#17131
This addresses a review comment left by tusharsnx in #17092 which I
forgot to fix before merging the PR. The fix itself is somewhat simple:
`Terminal::SetSearchHighlightFocused` triggers a scroll if the target
is outside of the current (scrolled) viewport and avoiding the call
unless necessary fixes it. To do it properly though, I've split up
`Search::ResetIfStale` into `IsStale` and `Reset`. Now we can properly
detect staleness in advance and branch out the search reset cleanly.
Additionally, I've taken the liberty to replace the `IVector` in
`SearchResultRows` with a direct `const std::vector&` into `Searcher`.
This removes a bunch of code and makes it faster to boot.
## Validation Steps Performed
* Print lots of text
* Search a common letter
* Scroll up
* Doesn't scroll back down ✅
* Hold enter to search more occurrences scrolls up as needed ✅
* `showMarksOnScrollbar` still works ✅
## Summary of the Pull Request
Fixed default selection background colors with light schemes. Default
color now matches the scheme and contrasts well
## References and Relevant Issues
none
## Detailed Description of the Pull Request / Additional comments
This is my first contribution ever :) Even though its simple, im happy
to help
## Validation Steps Performed
## PR Checklist
- [ ] Closes#8716
- [ ] 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 (if necessary)
These changes were automatically generated by clang-tidy.
```
clang-tidy --checks=modernize-avoid-bind --fix
```
I have not bothered with the test code.
---------
Co-authored-by: Mike Griese <migrie@microsoft.com>