diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs index c0daee8127246..c2a2e4dffec44 100644 --- a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs +++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs @@ -4,7 +4,6 @@ using System; using System.Composition; -using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -16,7 +15,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Navigation; @@ -59,8 +57,6 @@ internal sealed partial class SemanticSearchToolWindowImpl( VisualStudioWorkspace workspace, IStreamingFindUsagesPresenter resultsPresenter, ITextUndoHistoryRegistry undoHistoryRegistry, - ISemanticSearchCopilotService copilotService, - Lazy copilotUIProvider, // lazy to avoid loading Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot IVsService vsUIShellProvider) : IDisposable { private const int ToolBarHeight = 26; @@ -120,9 +116,7 @@ private async Task CreateContentAsync(CancellationToken cancel var vsUIShell = await vsUIShellProvider.GetValueAsync(cancellationToken).ConfigureAwait(false); - var copilotUI = CreateCopilotUI(); - - var textViewHost = CreateTextViewHost(vsUIShell, copilotUI); + var textViewHost = CreateTextViewHost(vsUIShell); var textViewControl = textViewHost.HostControl; _textView = textViewHost.TextView; _textBuffer = textViewHost.TextView.TextBuffer; @@ -167,11 +161,6 @@ private async Task CreateContentAsync(CancellationToken cancel toolWindowGrid.Children.Add(toolbarGrid); - if (copilotUI != null) - { - toolWindowGrid.Children.Add(copilotUI.Control); - } - toolWindowGrid.Children.Add(textViewControl); toolbarGrid.Children.Add(executeButton); toolbarGrid.Children.Add(cancelButton); @@ -181,12 +170,6 @@ private async Task CreateContentAsync(CancellationToken cancel Grid.SetRow(toolbarGrid, 0); Grid.SetColumn(toolbarGrid, 0); - if (copilotUI != null) - { - Grid.SetRow(copilotUI.Control, 1); - Grid.SetColumn(copilotUI.Control, 0); - } - Grid.SetRow(textViewControl, 2); Grid.SetColumn(textViewControl, 0); @@ -205,106 +188,6 @@ private async Task CreateContentAsync(CancellationToken cancel return toolWindowGrid; } - private CopilotUI? CreateCopilotUI() - { - if (!copilotUIProvider.Value.IsAvailable || !copilotService.IsAvailable) - { - return null; - } - - if (!globalOptions.GetOption(SemanticSearchFeatureFlag.PromptEnabled)) - { - return null; - } - - var outerGrid = new Grid() - { - Background = (Brush)Application.Current.FindResource(CommonControlsColors.TextBoxBackgroundBrushKey), - }; - - ImageThemingUtilities.SetImageBackgroundColor(outerGrid, (Color)Application.Current.Resources[CommonDocumentColors.PageBackgroundColorKey]); - ThemedDialogStyleLoader.SetUseDefaultThemedDialogStyles(outerGrid, true); - - // [ prompt border | empty ] - outerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); - outerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); - - var promptGrid = new Grid(); - - // [ input | panel ] - promptGrid.ColumnDefinitions.Add(new ColumnDefinition { MaxWidth = 600, Width = GridLength.Auto }); - promptGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); - - var promptTextBox = copilotUIProvider.Value.GetTextBox(); - - var panel = new StackPanel() - { - Orientation = Orientation.Horizontal, - HorizontalAlignment = HorizontalAlignment.Left, - VerticalAlignment = VerticalAlignment.Bottom, - Margin = new Thickness(8, 8, 0, 8), - }; - - Grid.SetColumn(promptTextBox.Control, 0); - promptGrid.Children.Add(promptTextBox.Control); - - Grid.SetColumn(panel, 1); - promptGrid.Children.Add(panel); - - var promptGridBorder = new Border - { - Name = "PromptBorder", - BorderBrush = (Brush)Application.Current.Resources[EnvironmentColors.SystemHighlightBrushKey], - BorderThickness = new Thickness(1), - Child = promptGrid - }; - - Grid.SetColumn(promptGridBorder, 0); - outerGrid.Children.Add(promptGridBorder); - - // ComboBox for model selection - var modelPicker = new ComboBox - { - SelectedIndex = 0, - HorizontalAlignment = HorizontalAlignment.Right, - VerticalAlignment = VerticalAlignment.Top, - Margin = new Thickness(4, 0, 4, 0), - Height = 24, - IsEditable = false, - IsReadOnly = true, - BorderThickness = new Thickness(0), - MinHeight = 24, - VerticalContentAlignment = VerticalAlignment.Top, - TabIndex = 1, - Style = (Style)Application.Current.FindResource(VsResourceKeys.ComboBoxStyleKey) - }; - - modelPicker.Items.Add("gpt-4o"); - modelPicker.Items.Add("gpt-4o-mini"); - modelPicker.Items.Add("o1"); - modelPicker.Items.Add("o1-ga"); - modelPicker.Items.Add("o1-mini"); - - panel.Children.Add(modelPicker); - - var submitButton = CreateButton( - KnownMonikers.Send, - automationName: "Generate query", - acceleratorKey: "Ctrl+Enter", - toolTip: "Generate query"); - - panel.Children.Add(submitButton); - - submitButton.Click += (_, _) => SubmitCopilotQuery(promptTextBox.Text, modelPicker.Text); - - return new CopilotUI() - { - Control = outerGrid, - Input = promptTextBox, - ModelPicker = modelPicker, - }; - } - private static Button CreateButton( Imaging.Interop.ImageMoniker moniker, string automationName, @@ -383,7 +266,7 @@ private static ControlTemplate CreateButtonTemplate() """, context); } - private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell, CopilotUI? copilotUI) + private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell) { Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread); @@ -422,7 +305,7 @@ private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell, CopilotUI? cop ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID.VSFPROPID_ViewHelper, textViewAdapter)); - _ = new CommandFilter(this, textViewAdapter, copilotUI); + _ = new CommandFilter(this, textViewAdapter); return textViewHost; } @@ -448,62 +331,6 @@ private void UpdateUIState() _cancelButton.IsEnabled = isExecuting; } - private void SubmitCopilotQuery(string input, string model) - { - Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread); - Contract.ThrowIfNull(_textBuffer); - Contract.ThrowIfNull(copilotService); - - // TODO: hook up cancel button for copilot queries - var cancellationSource = new CancellationTokenSource(); - - // TODO: fade out current content and show overlay spinner - - var completionToken = _asyncListener.BeginAsyncOperation(nameof(SemanticSearchToolWindow) + "." + nameof(SubmitCopilotQuery)); - _ = ExecuteAsync(cancellationSource.Token).ReportNonFatalErrorAsync().CompletesAsyncOperation(completionToken); - - async Task ExecuteAsync(CancellationToken cancellationToken) - { - await TaskScheduler.Default; - - SemanticSearchCopilotGeneratedQuery query; - - // TODO: generate list from SemanticSearch.ReferenceAssemblies: - var codeAnalysisVersion = new Version(4, 14, 0); - var sdkVersion = new Version(9, 0, 0); - - var context = new SemanticSearchCopilotContext() - { - ModelName = model, - AvailablePackages = - [ - ("Microsoft.CodeAnalysis", codeAnalysisVersion), - ("Microsoft.CodeAnalysis.CSharp", codeAnalysisVersion), - ("System.Collections.Immutable", sdkVersion), - ("System.Collections", sdkVersion), - ("System.Linq", sdkVersion), - ("System.Runtime", sdkVersion), - ] - }; - - try - { - query = await copilotService.TryGetQueryAsync(input, context, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken, ErrorSeverity.Critical)) - { - return; - } - catch (OperationCanceledException) - { - return; - } - - await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(CancellationToken.None); - SetEditorText(query.Text); - } - } - /// /// Replaces current text buffer content with specified . Allow using Ctrl+Z to revert to the previous content. /// Must be invoked on UI thread. @@ -613,36 +440,19 @@ public NavigableLocation GetNavigableLocation(TextSpan textSpan) return true; }); - private sealed class CopilotUI - { - public required FrameworkElement Control { get; init; } - public required ITextBoxControl Input { get; init; } - public required ComboBox ModelPicker { get; init; } - } - private sealed class CommandFilter : IOleCommandTarget { private readonly SemanticSearchToolWindowImpl _window; private readonly IOleCommandTarget _editorCommandTarget; - private readonly CopilotUI? _copilotUI; - public CommandFilter(SemanticSearchToolWindowImpl window, IVsTextView textView, CopilotUI? copilotUI) + public CommandFilter(SemanticSearchToolWindowImpl window, IVsTextView textView) { _window = window; - _copilotUI = copilotUI; ErrorHandler.ThrowOnFailure(textView.AddCommandFilter(this, out _editorCommandTarget)); } - [MemberNotNullWhen(true, nameof(_copilotUI))] - private bool HasCopilotInputFocus - => _copilotUI?.Input.View.HasAggregateFocus == true; - public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) - { - var target = HasCopilotInputFocus ? _copilotUI.Input.CommandTarget : _editorCommandTarget; - - return target.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); - } + => _editorCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { @@ -651,12 +461,6 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv switch ((VSConstants.VSStd2KCmdID)nCmdID) { case VSConstants.VSStd2KCmdID.OPENLINEABOVE: - if (HasCopilotInputFocus) - { - _window.SubmitCopilotQuery(_copilotUI.Input.Text, _copilotUI.ModelPicker.Text); - return VSConstants.S_OK; - } - if (!_window.IsExecutingUIState()) { _window.RunQuery(); @@ -676,8 +480,7 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv } } - var target = HasCopilotInputFocus ? _copilotUI.Input.CommandTarget : _editorCommandTarget; - return target.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + return _editorCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); } } } diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs index bf6719c76366f..ad1367fca50a6 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -368,7 +368,6 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_unsupported_report_invalid_json_patterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ReportInvalidJsonPatterns")}, {"visual_studio_enable_key_binding_reset", new FeatureFlagStorage("Roslyn.KeybindingResetEnabled")}, {"visual_studio_enable_semantic_search", new FeatureFlagStorage("Roslyn.SemanticSearchEnabled")}, - {"visual_studio_enable_semantic_search_prompt", new FeatureFlagStorage("Roslyn.ShowPromptInSemanticSearch")}, {"visual_studio_enable_copilot_rename_context", new FeatureFlagStorage("Roslyn.CopilotRenameGetContext")}, {"visual_studio_key_binding_needs_reset", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeedsReset")}, {"visual_studio_key_binding_reset_never_show_again", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeverShowAgain")}, diff --git a/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs b/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs index caf12828d2004..4b5e4cadb7d7d 100644 --- a/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs +++ b/src/VisualStudio/Core/Def/SemanticSearch/SemanticSearchFeatureFlag.cs @@ -9,7 +9,6 @@ namespace Microsoft.VisualStudio.LanguageServices; internal static class SemanticSearchFeatureFlag { public static readonly Option2 Enabled = new("visual_studio_enable_semantic_search", defaultValue: false); - public static readonly Option2 PromptEnabled = new("visual_studio_enable_semantic_search_prompt", defaultValue: false); /// /// Context id that indicates that Semantic Search feature is enabled. diff --git a/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs b/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs deleted file mode 100644 index 12966f1629140..0000000000000 --- a/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Composition; -using System.Windows.Controls; -using Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.SemanticSearch; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Text.Editor; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch; - -[Export(typeof(ISemanticSearchCopilotUIProvider)), Shared] -[method: ImportingConstructor] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class SemanticSearchCopilotUIProviderWrapper( - [Import(AllowDefault = true)] Lazy? impl) : ISemanticSearchCopilotUIProvider -{ - private sealed class TextBoxWrapper(ITextBoxControlImpl impl) : ITextBoxControl - { - Control ITextBoxControl.Control => impl.Control; - string ITextBoxControl.Text { get => impl.Text; set => impl.Text = value; } - IOleCommandTarget ITextBoxControl.CommandTarget => impl.CommandTarget; - IWpfTextView ITextBoxControl.View => impl.View; - } - - bool ISemanticSearchCopilotUIProvider.IsAvailable - => impl != null; - - ITextBoxControl ISemanticSearchCopilotUIProvider.GetTextBox() - { - Contract.ThrowIfNull(impl); - return new TextBoxWrapper(impl.Value.GetTextBox()); - } -}