Repository: microsoft/terminal (language: cpp)

Issue:
Filtering the search to display 0 actions does not clear the preview
sshhh bot


Discussion / hints:
Hi! Thanks for attempting to open an issue. Unfortunately, you didn't write anything in the body which makes it impossible to understand your concern. You are welcome to fix up the issue and try again by opening another issue with the body filled out. 
<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->

Fix patch:
diff --git a/src/cascadia/TerminalApp/SuggestionsControl.cpp b/src/cascadia/TerminalApp/SuggestionsControl.cpp
index e6f482ac19e..80206ea5ddd 100644
--- a/src/cascadia/TerminalApp/SuggestionsControl.cpp
+++ b/src/cascadia/TerminalApp/SuggestionsControl.cpp
@@ -269,6 +269,8 @@ namespace winrt::TerminalApp::implementation
         const auto selectedCommand = _filteredActionsView().SelectedItem();
         const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
 
+        _filteredActionsView().ScrollIntoView(selectedCommand);
+
         PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"SelectedItem" });
 
         // Make sure to not send the preview if we're collapsed. This can
@@ -795,14 +797,46 @@ namespace winrt::TerminalApp::implementation
         // here will ensure that we can check this case appropriately.
         _lastFilterTextWasEmpty = _searchBox().Text().empty();
 
-        const auto lastSelectedIndex = _filteredActionsView().SelectedIndex();
+        const auto lastSelectedIndex = std::max(0, _filteredActionsView().SelectedIndex()); // SelectedIndex will return -1 for "nothing"
 
         _updateFilteredActions();
 
-        // In the command line mode we want the user to explicitly select the command
-        _filteredActionsView().SelectedIndex(std::min<int32_t>(lastSelectedIndex, _filteredActionsView().Items().Size() - 1));
+        if (const auto newSelectedIndex = _filteredActionsView().SelectedIndex();
+            newSelectedIndex == -1)
+        {
+            // Make sure something stays selected
+            _scrollToIndex(lastSelectedIndex);
+        }
+        else
+        {
+            // BODGY: Calling ScrollIntoView on a ListView doesn't always work
+            // immediately after a change to the items. See:
+            // https://stackoverflow.com/questions/16942580/why-doesnt-listview-scrollintoview-ever-work
+            // The SelectionChanged thing we do (in _selectedCommandChanged),
+            // but because we're also not changing the actual selected item when
+            // the size of the list grows (it _stays_ selected, so it never
+            // _changes_), we never get a SelectionChanged.
+            //
+            // To mitigate, only in the case of totally clearing out the filter
+            // (like hitting `esc`), we want to briefly select the 0th item,
+            // then immediately select the one we want to make visible. That
+            // will make sure we get a SelectionChanged when the ListView is
+            // ready, and we can use that to scroll to the right item.
+            //
+            // If we do this on _every_ change, then the preview text flickers
+            // between the 0th item and the correct one.
+            if (_lastFilterTextWasEmpty)
+            {
+                _filteredActionsView().SelectedIndex(0);
+            }
+            _scrollToIndex(newSelectedIndex);
+        }
 
         const auto currentNeedleHasResults{ _filteredActions.Size() > 0 };
+        if (!currentNeedleHasResults)
+        {
+            PreviewAction.raise(*this, nullptr);
+        }
         _noMatchesText().Visibility(currentNeedleHasResults ? Visibility::Collapsed : Visibility::Visible);
         if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(_searchBox()) })
         {
@@ -1203,7 +1237,7 @@ namespace winrt::TerminalApp::implementation
         if (_direction == TerminalApp::SuggestionsDirection::BottomUp)
         {
             const auto last = _filteredActionsView().Items().Size() - 1;
-            _filteredActionsView().SelectedIndex(last);
+            _scrollToIndex(last);
         }
         // Move the cursor to the very last position, so it starts immediately
         // after the text. This is apparently done by starting a 0-wide


Test patch: