Conversation
| } | ||
|
|
||
| AppLogic::AppLogic() : | ||
| _reloadState{ std::chrono::milliseconds(100), []() { ApplicationState::SharedInstance().Reload(); } } |
There was a problem hiding this comment.
I believe not monitoring state.json for changes anymore is important as it prevents disturbing the session state while session persistence is still ongoing. That's because when ApplicationState flushes to disk, this FS monitor will be triggered and reload the ApplicationState again.
I figured it's not a problem anymore to do this since we're effectively a singleton application now.
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.
5dbb09a to
f9511d9
Compare
|
notes:
|
zadjii-msft
left a comment
There was a problem hiding this comment.
Most of this I'm cool with, but I have a couple last questions. Honestly, not as scary as I expected
|
|
||
| void ControlCore::PersistToPath(const wchar_t* path) const | ||
| { | ||
| const wil::unique_handle file{ CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) }; |
There was a problem hiding this comment.
kinda weird to me that the actual mechanics of reading/writing the file are down at the level of the control.
Benefit is that the file contents don't need to ever traverse a winrt boundary. And theoretically, anyone using a TermControl could then also get fairly trivial session restore from a file.
Downsides: we can't reuse our file loader (that Dustin's moving in #15329 so maybe this isn't important), and should other consumers get this? I suppose why not?
Okay I think I'm on board
| { | ||
| const auto settingsDir = CascadiaSettings::SettingsDirectory(); | ||
| const auto idStr = Utils::GuidToPlainString(id); | ||
| const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr); |
There was a problem hiding this comment.
some part of me wants to abstract out this fmt::format call to a common util lib, so that the app and control don't need to be updated in parallel if we change this, but also meh
There was a problem hiding this comment.
Yeah, I also felt a bit disgusted about putting this here, especially when considering the counterpart in WindowEmperor. But I couldn't come up with a good way to put it anywhere else. I think the saving grace of this code is that it's at least encapsulated to just 3 "small" sections of TerminalPage and WindowEmperor.
There was a problem hiding this comment.
funny enough, it was my plan to add support for automatic recordings which would use state/sessionIdGuid files!
zadjii-msft
left a comment
There was a problem hiding this comment.
I'm commander Shepard, and this is my favorite release of the Terminal
DHowett
left a comment
There was a problem hiding this comment.
Honestly I am exceptionally cool with this. Everything makes sense, it simplifies the state persistence logic severely, and it gives us a generic TextBuffer -> VT function (!)
src/buffer/out/TextColor.h
Outdated
| return _index; | ||
| } | ||
|
|
||
| BYTE GetIndex() const noexcept; |
There was a problem hiding this comment.
dumb question - does moving this out of the header harm the inlineability of it? does LTCG largely help with that?
There was a problem hiding this comment.
inline isn't a hint for inlining anymore, so it shouldn't make any difference. LTCG makes no difference either I think, because if anything it's probably inlined during initial compilation already due to its small size.
There was a problem hiding this comment.
Ah, I don't mean because of the inline keyword. Method bodies in header files can be inlined automatically, by the compiler, without the linker's help (LTCG). If you move the body into the cpp file, it can't be inlined during initial compilation because the compiler can only see the body from a single translation unit. It would require LTCG to come through and inline it at the call sites, now, because the other translation units couldn't see the body at compile time.
There was a problem hiding this comment.
Ah good point. This would be a good reason to move it back to the header.
| <value>Open with the given profile. Accepts either the name or GUID of a profile</value> | ||
| </data> | ||
| <data name="CmdSessionIdArgDesc" xml:space="preserve"> | ||
| <value>Sets the WT_SESSION variable</value> |
There was a problem hiding this comment.
| <value>Sets the WT_SESSION variable</value> | |
| <value>Sets the WT_SESSION variable; must be a GUID</value> |
maybe? or, is there an opportunity for like, yeeting an environment variable injection into this arg?
| { | ||
| const auto settingsDir = CascadiaSettings::SettingsDirectory(); | ||
| const auto idStr = Utils::GuidToPlainString(id); | ||
| const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr); |
There was a problem hiding this comment.
funny enough, it was my plan to add support for automatic recordings which would use state/sessionIdGuid files!
| } | ||
| } | ||
|
|
||
| const auto lock = _terminal->LockForReading(); |
There was a problem hiding this comment.
this is the read lock, should it be the write lock?
|
|
||
| Boolean EnableUnfocusedAcrylic; | ||
| Boolean EnableUnfocusedAcrylic { get; }; | ||
| Guid SessionId { get; }; |
There was a problem hiding this comment.
I didn't see this one get used; do we use it?
There was a problem hiding this comment.
Yes, via the TerminalSettings object to get the sessionId into the connection.
|
|
||
| // This returns something akin to %LOCALAPPDATA%\Packages\WindowsTerminalDev_8wekyb3d8bbwe\LocalState | ||
| // just like SettingsPath(), but without the trailing \settings.json. | ||
| winrt::hstring CascadiaSettings::SettingsDirectory() |
There was a problem hiding this comment.
Oh dang! @zadjii-msft you could have used this for WT_SETTINGS_DIR
There was a problem hiding this comment.
THATS WHY I thought this method already existed!
| si.cb = sizeof(si); | ||
| wil::unique_process_information pi; | ||
|
|
||
| LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(nullptr, |
There was a problem hiding this comment.
holy sh--, multi-window restore starts WindowsTerminal.exe which then gets a handle to our Monarch and sends it a commandline.
What the heck.
We could just... use Monarch directly here. I know you didn't write this code but I think we missed it when we migrated to single-proc.
There was a problem hiding this comment.
Yup. I felt like it would be too off-topic if I changed this part within the PR. But I agree that it's ripe for a refactoring.
|
FYI the merge commit is non-trivial. If you do want to review my latest changes, you may have to review the merge as well. |
| static constexpr Mapping mappings[] = { | ||
| { CharacterAttributes::Intense, { 22, 1 } }, | ||
| { CharacterAttributes::Italics, { 23, 3 } }, | ||
| { CharacterAttributes::Blinking, { 25, 5 } }, | ||
| { CharacterAttributes::Invisible, { 28, 8 } }, | ||
| { CharacterAttributes::CrossedOut, { 29, 9 } }, | ||
| { CharacterAttributes::Faint, { 22, 2 } }, | ||
| { CharacterAttributes::TopGridline, { 55, 53 } }, | ||
| { CharacterAttributes::ReverseVideo, { 27, 7 } }, | ||
| { CharacterAttributes::BottomGridline, { 24, 4 } }, | ||
| }; | ||
| for (const auto& mapping : mappings) | ||
| { | ||
| if (WI_IsAnyFlagSet(attrDelta, mapping.attr)) | ||
| { | ||
| const auto n = til::at(mapping.change, WI_IsAnyFlagSet(attr, mapping.attr)); | ||
| fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[{}m"), n); | ||
| } | ||
| } |
There was a problem hiding this comment.
I don't think this will work correctly when mixing intense and faint. For example, a sequence like \e[1mBOLD\e[2mBOTH\e[0;2mFAINT will assumedly serialize as \e[1mBOLD\e[2mBOTH\e[22mFAINT, which isn't correct (the FAINT text won't be faint).
It's also worth mentioning that BottomGridLine isn't the same as underline - we don't have a VT mapping for that. So AFAIK, it shouldn't ever show up in the Windows Terminal buffer.
There was a problem hiding this comment.
Oh, I didn't even notice that I used 22 twice. Thanks for noticing this!
I've opened #16970 which should fix both issues.
zadjii-msft
left a comment
There was a problem hiding this comment.
I'm fine dealing with the intense/faint thing in post.
This got lost in #16598. `TerminalPage` needs to ask the window where the it actually is, so it can persist it. More details in #16598 (comment) Closes #17010
This contains all the changes of 5dda507, c4c5206, 9f08ee7, and 5f10159 (#16598 and all related PRs), but without the buffer restore feature. The hope is that these changes fix some rarer issues we've been hearing about, where persistence doesn't work correctly. ## Validation Steps Performed This changeset was tested on Windows 11 with 2 windows and 4 tabs where 1 tab had 2 mixed split panes. All windows and tabs got restored properly. It didn't crash on Windows 10.
This got lost in #16598. `TerminalPage` needs to ask the window where the it actually is, so it can persist it. More details in #16598 (comment) Closes #17010 (cherry picked from commit 643f716) Service-Card-Id: 92360686 Service-Version: 1.20
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
persistedWindowLayoutis being used.Closes #961
Closes #16741
Validation Steps Performed
Everything's restored ✅
RenderingTests.exeEverything's restored ✅