Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a proper tool bar in Document Outline #68094

Merged
merged 6 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -73,37 +73,11 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="23" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Name="Commands" Focusable="True" />
<TextBox Grid.Row="1" x:Name="SearchBox" TextChanged="SearchBox_TextChanged" VerticalContentAlignment="Center">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Background" Value="{StaticResource {x:Static vsshell:VsBrushes.ToolWindowBackgroundKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static vsshell:VsBrushes.ToolWindowTextKey}}" />
<Setter Property="Padding" Value="3, 0, 0, 0" />
<Setter Property="FontFamily" Value="{StaticResource {x:Static vsshell:VsFonts.CaptionFontFamilyKey}}" />
<Setter Property="FontSize" Value="{StaticResource {x:Static vsshell:VsFonts.CaptionFontSizeKey}}" />
<Setter Property="CaretBrush" Value="{StaticResource {x:Static vsui:HeaderColors.DefaultTextBrushKey}}" />
<Style.Resources>
<VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="{x:Static self:DocumentOutlineStrings.Document_Outline_Search}"
Foreground="{DynamicResource {x:Static vsshell:VsBrushes.TitleBarInactiveTextKey}}"
FontFamily="{StaticResource {x:Static vsshell:VsFonts.CaptionFontFamilyKey}}"
FontSize="{StaticResource {x:Static vsshell:VsFonts.CaptionFontSizeKey}}" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Grid Grid.Row="1" x:Name="SearchHost" />
<!-- Two important properties are being set for TreeView:
We set IsVirtualizing to "True" so that WPF only generates internal data-structures elements that are visible.
Setting VirtualizationMode to "Recycling" ensures that WPF internal data is reused as items scroll in and out of view.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,19 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices.Implementation;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using InternalUtilities = Microsoft.Internal.VisualStudio.PlatformUI.Utilities;
using IOleCommandTarget = Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget;
using OLECMD = Microsoft.VisualStudio.OLE.Interop.OLECMD;
using OLECMDF = Microsoft.VisualStudio.OLE.Interop.OLECMDF;
Expand All @@ -31,15 +27,17 @@ namespace Microsoft.VisualStudio.LanguageServices.DocumentOutline
/// Interaction logic for DocumentOutlineView.xaml
/// All operations happen on the UI thread for visual studio
/// </summary>
internal sealed partial class DocumentOutlineView : UserControl, IOleCommandTarget, IDisposable
internal sealed partial class DocumentOutlineView : UserControl, IOleCommandTarget, IDisposable, IVsWindowSearch
{
private readonly IThreadingContext _threadingContext;
private readonly VsCodeWindowViewTracker _viewTracker;
private readonly DocumentOutlineViewModel _viewModel;
private readonly IVsToolbarTrayHost _toolbarTrayHost;
private readonly IVsWindowSearchHost _windowSearchHost;

public DocumentOutlineView(
IVsUIShell4 uiShell,
IVsWindowSearchHostFactory windowSearchHostFactory,
IThreadingContext threadingContext,
VsCodeWindowViewTracker viewTracker,
DocumentOutlineViewModel viewModel)
Expand All @@ -60,19 +58,20 @@ public DocumentOutlineView(
ErrorHandler.ThrowOnFailure(((IVsUIWpfElement)uiObject).GetFrameworkElement(out var frameworkElement));
Commands.Content = frameworkElement;

_windowSearchHost = windowSearchHostFactory.CreateWindowSearchHost(SearchHost);
_windowSearchHost.SetupSearch(this);

viewTracker.CaretMovedOrActiveViewChanged += ViewTracker_CaretMovedOrActiveViewChanged;
}

public void Dispose()
{
_toolbarTrayHost.Close();
_windowSearchHost.TerminateSearch();
_viewTracker.CaretMovedOrActiveViewChanged -= ViewTracker_CaretMovedOrActiveViewChanged;
_viewModel.Dispose();
}

private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
=> _viewModel.SearchText = SearchBox.Text;

int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
if (pguidCmdGroup == Guids.RoslynGroupId)
Expand Down Expand Up @@ -122,7 +121,7 @@ int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] p
return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
}

public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
int IOleCommandTarget.Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
if (pguidCmdGroup == Guids.RoslynGroupId)
{
Expand Down Expand Up @@ -153,6 +152,45 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv
return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
}

bool IVsWindowSearch.SearchEnabled => true;

Guid IVsWindowSearch.Category => Guids.DocumentOutlineSearchCategoryId;

IVsEnumWindowSearchFilters? IVsWindowSearch.SearchFiltersEnum => null;

IVsEnumWindowSearchOptions? IVsWindowSearch.SearchOptionsEnum => null;

IVsSearchTask IVsWindowSearch.CreateSearch(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchCallback pSearchCallback)
{
_viewModel.SearchText = pSearchQuery.SearchString;
return new VsSearchTask(dwCookie, pSearchQuery, pSearchCallback);
}

void IVsWindowSearch.ClearSearch()
{
_viewModel.SearchText = "";
}

void IVsWindowSearch.ProvideSearchSettings(IVsUIDataSource pSearchSettings)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, I've never seen this before.

{
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.ControlMaxWidth, uint.MaxValue);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchStartType, (uint)VSSEARCHSTARTTYPE.SST_DELAYED);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchStartDelay, (uint)100);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchUseMRU, true);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.PrefixFilterMRUItems, false);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.MaximumMRUItems, (uint)25);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchWatermark, ServicesVSResources.Document_Outline_Search);
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchPopupAutoDropdown, false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this one do?

InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.ControlBorderThickness, "1");
InternalUtilities.SetValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchProgressType, (uint)VSSEARCHPROGRESSTYPE.SPT_INDETERMINATE);
}

bool IVsWindowSearch.OnNavigationKeyDown(uint dwNavigationKey, uint dwModifiers)
{
// By default we are not interesting in intercepting navigation keys, so return "not handled"
return false;
}

private void UpdateSort(SortOption sortOption)
{
_threadingContext.ThrowIfNotOnUIThread();
Expand Down
3 changes: 3 additions & 0 deletions src/VisualStudio/Core/Def/Guids.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ internal static class Guids
public const string StackTraceExplorerCommandIdString = "FB190424-4DFF-43DB-8CCA-E32D1CE8A5CA";
public static readonly Guid StackTraceExplorerCommandId = new(StackTraceExplorerCommandIdString);

public const string DocumentOutlineSearchCategoryIdString = "C80E47CF-B95A-46D4-8BE4-6ADA02888333";
public static readonly Guid DocumentOutlineSearchCategoryId = new(DocumentOutlineSearchCategoryIdString);

// TODO: Remove pending https://github.com/dotnet/roslyn/issues/8927 .
// Interactive guids
public const string InteractiveCommandSetIdString = "00B8868B-F9F5-4970-A048-410B05508506";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ private void GetOutline(out IntPtr phwnd)
threadingContext.ThrowIfNotOnUIThread();

var uiShell = (IVsUIShell4)_languageService.SystemServiceProvider.GetService(typeof(SVsUIShell));
var windowSearchHostFactory = (IVsWindowSearchHostFactory)_languageService.SystemServiceProvider.GetService(typeof(SVsWindowSearchHostFactory));
var languageServiceBroker = _languageService.Package.ComponentModel.GetService<ILanguageServiceBroker2>();
var asyncListenerProvider = _languageService.Package.ComponentModel.GetService<IAsynchronousOperationListenerProvider>();
var asyncListener = asyncListenerProvider.GetListener(FeatureAttribute.DocumentOutline);
Expand All @@ -269,7 +270,7 @@ private void GetOutline(out IntPtr phwnd)

var viewTracker = new VsCodeWindowViewTracker(_codeWindow, threadingContext, editorAdaptersFactoryService);
_documentOutlineView = new DocumentOutlineView(
uiShell, threadingContext, viewTracker,
uiShell, windowSearchHostFactory, threadingContext, viewTracker,
new DocumentOutlineViewModel(threadingContext, viewTracker, languageServiceBroker, asyncListener));

_documentOutlineViewHost = new ElementHost
Expand Down