-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19366 from 333fred/info-bar-refactor
Refactored IErrorReportingService
- Loading branch information
Showing
15 changed files
with
309 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/EditorFeatures/Core/Implementation/InfoBar/EditorInfoBarService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Composition; | ||
using Microsoft.CodeAnalysis.Extensions; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
using Microsoft.CodeAnalysis.Internal.Log; | ||
|
||
namespace Microsoft.CodeAnalysis.Editor.Implementation.Workspaces | ||
{ | ||
[ExportWorkspaceService(typeof(IInfoBarService)), Shared] | ||
internal class EditorInfoBarService : IInfoBarService | ||
{ | ||
public void ShowInfoBarInActiveView(string message, params InfoBarUI[] items) | ||
=> ShowInfoBarInGlobalView(message, items); | ||
|
||
public void ShowInfoBarInGlobalView(string message, params InfoBarUI[] items) | ||
=> Logger.Log(FunctionId.Extension_InfoBar, message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
206 changes: 206 additions & 0 deletions
206
src/VisualStudio/Core/Def/Implementation/InfoBar/VisualStudioInfoBarService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Composition; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis.Editor; | ||
using Microsoft.CodeAnalysis.Editor.Shared.Utilities; | ||
using Microsoft.CodeAnalysis.Extensions; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
using Microsoft.CodeAnalysis.Shared.TestHooks; | ||
using Microsoft.VisualStudio.Imaging; | ||
using Microsoft.VisualStudio.Shell; | ||
using Microsoft.VisualStudio.Shell.Interop; | ||
using Roslyn.Utilities; | ||
|
||
namespace Microsoft.VisualStudio.LanguageServices.Implementation | ||
{ | ||
[ExportWorkspaceService(typeof(IInfoBarService), layer: ServiceLayer.Host), Shared] | ||
internal class VisualStudioInfoBarService : ForegroundThreadAffinitizedObject, IInfoBarService | ||
{ | ||
private readonly SVsServiceProvider _serviceProvider; | ||
private readonly IForegroundNotificationService _foregroundNotificationService; | ||
private readonly IAsynchronousOperationListener _listener; | ||
|
||
[ImportingConstructor] | ||
public VisualStudioInfoBarService(SVsServiceProvider serviceProvider, | ||
IForegroundNotificationService foregroundNotificationService, | ||
[ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners) | ||
{ | ||
_serviceProvider = serviceProvider; | ||
_foregroundNotificationService = foregroundNotificationService; | ||
_listener = new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.InfoBar); | ||
} | ||
|
||
public void ShowInfoBarInActiveView(string message, params InfoBarUI[] items) | ||
{ | ||
ThisCanBeCalledOnAnyThread(); | ||
ShowInfoBar(activeView: true, message: message, items: items); | ||
} | ||
|
||
public void ShowInfoBarInGlobalView(string message, params InfoBarUI[] items) | ||
{ | ||
ThisCanBeCalledOnAnyThread(); | ||
ShowInfoBar(activeView: false, message: message, items: items); | ||
} | ||
|
||
private void ShowInfoBar(bool activeView, string message, params InfoBarUI[] items) | ||
{ | ||
// We can be called from any thread since errors can occur anywhere, however we can only construct and InfoBar from the UI thread. | ||
_foregroundNotificationService.RegisterNotification(() => | ||
{ | ||
if (TryGetInfoBarData(activeView, out var infoBarHost)) | ||
{ | ||
CreateInfoBar(infoBarHost, message, items); | ||
} | ||
}, _listener.BeginAsyncOperation(nameof(ShowInfoBar))); | ||
} | ||
|
||
private bool TryGetInfoBarData(bool activeView, out IVsInfoBarHost infoBarHost) | ||
{ | ||
AssertIsForeground(); | ||
|
||
infoBarHost = null; | ||
|
||
if (activeView) | ||
{ | ||
var monitorSelectionService = _serviceProvider.GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection; | ||
|
||
// We want to get whichever window is currently in focus (including toolbars) as we could have had an exception thrown from the error list | ||
// or interactive window | ||
if (monitorSelectionService == null || | ||
ErrorHandler.Failed(monitorSelectionService.GetCurrentElementValue((uint)VSConstants.VSSELELEMID.SEID_WindowFrame, out var value))) | ||
{ | ||
return false; | ||
} | ||
|
||
var frame = value as IVsWindowFrame; | ||
if (ErrorHandler.Failed(frame.GetProperty((int)__VSFPROPID7.VSFPROPID_InfoBarHost, out var activeViewInfoBar))) | ||
{ | ||
return false; | ||
} | ||
|
||
infoBarHost = activeViewInfoBar as IVsInfoBarHost; | ||
return infoBarHost != null; | ||
} | ||
|
||
// global error info, show it on main window info bar | ||
var shell = _serviceProvider.GetService(typeof(SVsShell)) as IVsShell; | ||
if (shell == null || | ||
ErrorHandler.Failed(shell.GetProperty((int)__VSSPROPID7.VSSPROPID_MainWindowInfoBarHost, out var globalInfoBar))) | ||
{ | ||
return false; | ||
} | ||
|
||
infoBarHost = globalInfoBar as IVsInfoBarHost; | ||
return infoBarHost != null; | ||
} | ||
|
||
private void CreateInfoBar(IVsInfoBarHost infoBarHost, string message, InfoBarUI[] items) | ||
{ | ||
var factory = _serviceProvider.GetService(typeof(SVsInfoBarUIFactory)) as IVsInfoBarUIFactory; | ||
if (factory == null) | ||
{ | ||
// no info bar factory, don't do anything | ||
return; | ||
} | ||
|
||
var textSpans = new List<IVsInfoBarTextSpan>() | ||
{ | ||
new InfoBarTextSpan(message) | ||
}; | ||
|
||
// create action item list | ||
var actionItems = new List<IVsInfoBarActionItem>(); | ||
|
||
foreach (var item in items) | ||
{ | ||
switch (item.Kind) | ||
{ | ||
case InfoBarUI.UIKind.Button: | ||
actionItems.Add(new InfoBarButton(item.Title)); | ||
break; | ||
case InfoBarUI.UIKind.HyperLink: | ||
actionItems.Add(new InfoBarHyperlink(item.Title)); | ||
break; | ||
case InfoBarUI.UIKind.Close: | ||
break; | ||
default: | ||
throw ExceptionUtilities.UnexpectedValue(item.Kind); | ||
} | ||
} | ||
|
||
var infoBarModel = new InfoBarModel( | ||
textSpans, | ||
actionItems.ToArray(), | ||
KnownMonikers.StatusInformation, | ||
isCloseButtonVisible: true); | ||
|
||
if (!TryCreateInfoBarUI(factory, infoBarModel, out var infoBarUI)) | ||
{ | ||
return; | ||
} | ||
|
||
uint? infoBarCookie = null; | ||
var eventSink = new InfoBarEvents(items, () => | ||
{ | ||
// run given onClose action if there is one. | ||
items.FirstOrDefault(i => i.Kind == InfoBarUI.UIKind.Close).Action?.Invoke(); | ||
|
||
if (infoBarCookie.HasValue) | ||
{ | ||
infoBarUI.Unadvise(infoBarCookie.Value); | ||
} | ||
}); | ||
|
||
infoBarUI.Advise(eventSink, out var cookie); | ||
infoBarCookie = cookie; | ||
|
||
infoBarHost.AddInfoBar(infoBarUI); | ||
} | ||
|
||
private class InfoBarEvents : IVsInfoBarUIEvents | ||
{ | ||
private readonly InfoBarUI[] _items; | ||
private readonly Action _onClose; | ||
|
||
public InfoBarEvents(InfoBarUI[] items, Action onClose) | ||
{ | ||
Contract.ThrowIfNull(onClose); | ||
|
||
_items = items; | ||
_onClose = onClose; | ||
} | ||
|
||
public void OnActionItemClicked(IVsInfoBarUIElement infoBarUIElement, IVsInfoBarActionItem actionItem) | ||
{ | ||
var item = _items.FirstOrDefault(i => i.Title == actionItem.Text); | ||
if (item.IsDefault) | ||
{ | ||
return; | ||
} | ||
|
||
item.Action?.Invoke(); | ||
|
||
if (!item.CloseAfterAction) | ||
{ | ||
return; | ||
} | ||
|
||
infoBarUIElement.Close(); | ||
} | ||
|
||
public void OnClosed(IVsInfoBarUIElement infoBarUIElement) | ||
{ | ||
_onClose(); | ||
} | ||
} | ||
|
||
private static bool TryCreateInfoBarUI(IVsInfoBarUIFactory infoBarUIFactory, IVsInfoBar infoBar, out IVsInfoBarUIElement uiElement) | ||
{ | ||
uiElement = infoBarUIFactory.CreateInfoBar(infoBar); | ||
return uiElement != null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.