From 38386bb8a70a824429ffd149d5d2ecf5d74298f8 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 14 Sep 2023 15:30:50 -0500 Subject: [PATCH] a proof of concept for #3991 --- src/cascadia/TerminalControl/ControlCore.cpp | 76 +++++++++++++++++++- src/cascadia/TerminalControl/ControlCore.h | 6 ++ src/cascadia/TerminalCore/Terminal.cpp | 5 ++ src/cascadia/TerminalCore/Terminal.hpp | 2 + 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 52dc7d4087f..685804c0188 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -211,6 +211,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation core->_ScrollPositionChangedHandlers(*core, update); } }); + + shared->lookForOutput = std::make_unique>( + _dispatcher, + SearchAfterChangeDelay, + [/*weakTerminal = std::weak_ptr{ _terminal }, */ weakThis = get_weak()]() { + // if (const auto t = weakTerminal.lock()) + if (auto core{ weakThis.get() }; !core->_IsClosing()) + { + auto lock = core->_terminal->LockForWriting(); + if (core->_terminal->HasContentAfter(core->_restartedAt)) + { + core->_gotFirstByte = true; + core->_automaticProgressState = DispatchTypes::TaskbarState::Clear; + core->_TaskbarProgressChangedHandlers(*core, nullptr); + } + } + }); } ControlCore::~ControlCore() @@ -276,6 +293,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation { // Subscribe to the connection's disconnected event and call our connection closed handlers. _connectionStateChangedRevoker = newConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) { + // if (_connection.State() > TerminalConnection::ConnectionState::Connecting && + // _automaticProgressState == DispatchTypes::TaskbarState::Indeterminate) + // { + // _automaticProgressState = DispatchTypes::TaskbarState::Clear; + // _TaskbarProgressChangedHandlers(*this, nullptr); + // } _ConnectionStateChangedHandlers(*this, nullptr); }); @@ -296,6 +319,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation // This event is explicitly revoked in the destructor: does not need weak_ref _connectionOutputEventRevoker = _connection.TerminalOutput(winrt::auto_revoke, { this, &ControlCore::_connectionOutputHandler }); + + if (_connection.State() < TerminalConnection::ConnectionState::Connected) + { + _gotFirstByte = false; + _automaticProgressState = DispatchTypes::TaskbarState::Indeterminate; + _restartedAt = _initializedTerminal.load(std::memory_order_relaxed) ? _terminal->GetTextBuffer().GetLastNonSpaceCharacter() : _restartedAt; + _TaskbarProgressChangedHandlers(*this, nullptr); + } } // Fire off a connection state changed notification, to let our hosting @@ -1382,7 +1413,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - The taskbar state of this control const size_t ControlCore::TaskbarState() const noexcept { - return _terminal->GetTaskbarState(); + // The CLI's progress always takes precedence. + if (const auto progressStateFromApp{ _terminal->GetTaskbarState() }; + static_cast(progressStateFromApp) != DispatchTypes::TaskbarState::Clear) + { + return progressStateFromApp; + } + return static_cast(_automaticProgressState); // _terminal->GetTaskbarState(); } // Method Description: @@ -1391,7 +1428,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - The taskbar progress of this control const size_t ControlCore::TaskbarProgress() const noexcept { - return _terminal->GetTaskbarProgress(); + // The CLI's progress always takes precedence. + if (const auto progressStateFromApp{ _terminal->GetTaskbarState() }; + static_cast(progressStateFromApp) != DispatchTypes::TaskbarState::Clear) + { + return _terminal->GetTaskbarProgress(); + } + return _automaticProgress; // _terminal->GetTaskbarState(); } int ControlCore::ScrollOffset() @@ -1916,6 +1959,35 @@ namespace winrt::Microsoft::Terminal::Control::implementation } void ControlCore::_connectionOutputHandler(const hstring& hstr) { + if (!_gotFirstByte) + { + const auto shared = _shared.lock_shared(); + if (shared->lookForOutput) + { + shared->lookForOutput->Run(); + } + + // // ConPTY is known to send + // // * L"\x1b[?9001h\x1b[?1004h" + // // * L"\x1b[6n" + // // + // // on startup. It might be changed in the future. You might think a + // // useful heuristic would be wait till we get a sequence that + // // doesn't start with an esc char. You'd be wrong - for something + // // like bash, it's going to write a lot of frames that start with an + // // ESC. Even just typing - turns the cursor on and off, moves it, + // // clears the input line, etc. + // // if (!hstr.empty() && hstr != L'\x1b') + // if (hstr != L"\x1b[?9001h\x1b[?1004h" && hstr != L"\x1b[6n") + // { + // _gotFirstByte = true; + // _automaticProgressState = DispatchTypes::TaskbarState::Clear; + // // TODO! not on the output thread dingus + // // Though i guess the first one does too so that's okay + // _TaskbarProgressChangedHandlers(*this, nullptr); + // } + } + try { _terminal->Write(hstr); diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index c21730f4789..405409f6e9b 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -286,6 +286,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation std::shared_ptr> tsfTryRedrawCanvas; std::unique_ptr> updatePatternLocations; std::shared_ptr> updateScrollBar; + std::shared_ptr> lookForOutput; }; std::atomic _initializedTerminal{ false }; @@ -341,6 +342,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation til::point _contextMenuBufferPosition{ 0, 0 }; + ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState _automaticProgressState = ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState::Clear; + size_t _automaticProgress = 0; + bool _gotFirstByte{ false }; + til::point _restartedAt{ 0, 0 }; + Windows::Foundation::Collections::IVector _cachedSearchResultRows{ nullptr }; void _setupDispatcherAndCallbacks(); diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 40156064b3f..367b0cfeb2b 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -1626,3 +1626,8 @@ extern "C" SHORT OneCoreSafeGetKeyState(_In_ int nVirtKey) { return GetKeyState(nVirtKey); } + +bool Terminal::HasContentAfter(const til::point p) +{ + return p < _activeBuffer().GetLastNonSpaceCharacter(); +} diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 9c83710c3b5..b5a49995942 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -239,6 +239,8 @@ class Microsoft::Terminal::Core::Terminal final : void UpdatePatternsUnderLock(); void ClearPatternTree(); + bool HasContentAfter(const til::point at); + const std::optional GetTabColor() const; winrt::Microsoft::Terminal::Core::Scheme GetColorScheme() const;