Fix scrollbar marks not appearing until scroll or resize (#19185)

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

(cherry picked from commit e818dafa6db29cb67cc2418ba67e5e0846a6e9b4)
Service-Card-Id: PVTI_lADOAF3p4s4AxadtzgdFukU
Service-Version: 1.23
This commit is contained in:
Quaylyn Rimer 2025-07-29 10:20:47 -07:00 committed by Dustin L. Howett
parent 99c6de5bbe
commit edcd042913
7 changed files with 25 additions and 0 deletions

View File

@ -155,6 +155,7 @@ public:
bool IsVtInputEnabled() const noexcept override;
void NotifyAccessibilityChange(const til::rect& changedRect) noexcept override;
void NotifyBufferRotation(const int delta) override;
void NotifyShellIntegrationMark() override;
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;

View File

@ -404,3 +404,9 @@ void Terminal::NotifyBufferRotation(const int delta)
_NotifyScrollEvent();
}
}
void Terminal::NotifyShellIntegrationMark()
{
// Notify the scrollbar that marks have been added so it can refresh the mark indicators
_NotifyScrollEvent();
}

View File

@ -446,6 +446,11 @@ void ConhostInternalGetSet::NotifyBufferRotation(const int delta)
}
}
void ConhostInternalGetSet::NotifyShellIntegrationMark()
{
// Not implemented for conhost - shell integration marks are a Terminal app feature.
}
void ConhostInternalGetSet::InvokeCompletions(std::wstring_view /*menuJson*/, unsigned int /*replaceLength*/)
{
// Not implemented for conhost.

View File

@ -67,6 +67,7 @@ public:
void NotifyAccessibilityChange(const til::rect& changedRect) override;
void NotifyBufferRotation(const int delta) override;
void NotifyShellIntegrationMark() override;
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;

View File

@ -86,6 +86,7 @@ namespace Microsoft::Console::VirtualTerminal
virtual void NotifyAccessibilityChange(const til::rect& changedRect) = 0;
virtual void NotifyBufferRotation(const int delta) = 0;
virtual void NotifyShellIntegrationMark() = 0;
virtual void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) = 0;

View File

@ -3594,6 +3594,7 @@ void AdaptDispatch::DoConEmuAction(const std::wstring_view string)
else if (subParam == 12)
{
_pages.ActivePage().Buffer().StartCommand();
_api.NotifyShellIntegrationMark();
}
}
@ -3624,6 +3625,7 @@ void AdaptDispatch::DoITerm2Action(const std::wstring_view string)
if (action == L"SetMark")
{
_pages.ActivePage().Buffer().StartPrompt();
_api.NotifyShellIntegrationMark();
}
}
@ -3657,16 +3659,19 @@ void AdaptDispatch::DoFinalTermAction(const std::wstring_view string)
case L'A': // FTCS_PROMPT
{
_pages.ActivePage().Buffer().StartPrompt();
_api.NotifyShellIntegrationMark();
break;
}
case L'B': // FTCS_COMMAND_START
{
_pages.ActivePage().Buffer().StartCommand();
_api.NotifyShellIntegrationMark();
break;
}
case L'C': // FTCS_COMMAND_EXECUTED
{
_pages.ActivePage().Buffer().StartOutput();
_api.NotifyShellIntegrationMark();
break;
}
case L'D': // FTCS_COMMAND_FINISHED
@ -3687,6 +3692,7 @@ void AdaptDispatch::DoFinalTermAction(const std::wstring_view string)
}
_pages.ActivePage().Buffer().EndCurrentCommand(error);
_api.NotifyShellIntegrationMark();
break;
}

View File

@ -212,6 +212,11 @@ public:
Log::Comment(L"NotifyBufferRotation MOCK called...");
}
void NotifyShellIntegrationMark() override
{
Log::Comment(L"NotifyShellIntegrationMark MOCK called...");
}
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override
{
Log::Comment(L"InvokeCompletions MOCK called...");