React to API feedback on VisualStudioRazorParser.

- Changed `ReparseAsync` to be `QueueReparse`. It's now async void to not give the misconception that it blocks until a reparse has been completed.
- Removed `IContextChangedListener`. People can get the same effect of the interface by retrieving the document tracker interface via the `RazorEditorFactoryService` and then when its context changes getting the parser.
- Exposed `TryGetParser` to aid in replacing `IContextChangedListener`.
- Updated tests to not rely on `IContextChangedListener`.
This commit is contained in:
N. Taylor Mullen 2017-10-24 17:11:38 -07:00
Родитель d027697389
Коммит ab62ea9321
8 изменённых файлов: 17 добавлений и 99 удалений

Просмотреть файл

@ -30,7 +30,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
private readonly object IdleLock = new object();
private readonly ICompletionBroker _completionBroker;
private readonly IEnumerable<IContextChangedListener> _contextChangedListeners;
private readonly VisualStudioDocumentTracker _documentTracker;
private readonly ForegroundDispatcher _dispatcher;
private readonly RazorTemplateEngineFactoryService _templateEngineFactory;
@ -51,8 +50,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
VisualStudioDocumentTracker documentTracker,
RazorTemplateEngineFactoryService templateEngineFactory,
ErrorReporter errorReporter,
ICompletionBroker completionBroker,
IEnumerable<IContextChangedListener> contextChangedListeners)
ICompletionBroker completionBroker)
{
if (dispatcher == null)
{
@ -79,16 +77,10 @@ namespace Microsoft.VisualStudio.Editor.Razor
throw new ArgumentNullException(nameof(completionBroker));
}
if (contextChangedListeners == null)
{
throw new ArgumentNullException(nameof(contextChangedListeners));
}
_dispatcher = dispatcher;
_templateEngineFactory = templateEngineFactory;
_errorReporter = errorReporter;
_completionBroker = completionBroker;
_contextChangedListeners = contextChangedListeners;
_documentTracker = documentTracker;
_documentTracker.ContextChanged += DocumentTracker_ContextChanged;
@ -110,7 +102,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
// Used in unit tests to ensure we can block background idle work.
internal ManualResetEventSlim BlockBackgroundIdleWork { get; set; }
public override async Task ReparseAsync()
public override void QueueReparse()
{
// Can be called from any thread
@ -120,7 +112,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
else
{
await Task.Factory.StartNew(ReparseOnForeground, null, CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler);
Task.Factory.StartNew(ReparseOnForeground, null, CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler);
}
}
@ -145,11 +137,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
return;
}
NotifyParserContextChanged();
// We have a new parser, force a reparse to generate new document information. Note that this
// only blocks until the reparse change has been queued.
ReparseAsync().GetAwaiter().GetResult();
QueueReparse();
}
// Internal for testing
@ -171,21 +161,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
return true;
}
// Internal for testing
internal void NotifyParserContextChanged()
{
_dispatcher.AssertForegroundThread();
// This is temporary until we own the TagHelper resolution system. At that point the parser will push out updates
// via DocumentStructureChangedEvents when contexts change. For now, listeners need to know more information about
// the parser. In the case that the tracker does not belong to a supported project the editor will tear down its
// attachment to the parser when it recognizes the document closing.
foreach (var contextChangeListener in _contextChangedListeners)
{
contextChangeListener.OnContextChanged(this);
}
}
// Internal for testing
internal void StartParser()
{
@ -303,8 +278,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
}
// This only blocks until the reparse change has been queued.
ReparseAsync().GetAwaiter().GetResult();
QueueReparse();
}
private void ReparseOnForeground(object state)

Просмотреть файл

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.Editor.Razor
{
/// <summary>
/// This class will cease to be useful once the Razor tooling owns TagHelper discovery
/// </summary>
public interface IContextChangedListener
{
void OnContextChanged(VisualStudioRazorParser parser);
}
}

Просмотреть файл

@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
{
public abstract bool TryGetDocumentTracker(ITextBuffer textBuffer, out VisualStudioDocumentTracker documentTracker);
internal abstract bool TryGetParser(ITextBuffer textBuffer, out VisualStudioRazorParser parser);
public abstract bool TryGetParser(ITextBuffer textBuffer, out VisualStudioRazorParser parser);
internal abstract bool TryGetSmartIndenter(ITextBuffer textBuffer, out BraceSmartIndenter braceSmartIndenter);
}

Просмотреть файл

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.VisualStudio.Text;
@ -22,6 +21,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
public abstract ITextBuffer TextBuffer { get; }
public abstract Task ReparseAsync();
public abstract void QueueReparse();
}
}

Просмотреть файл

@ -69,7 +69,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
return true;
}
internal override bool TryGetParser(ITextBuffer textBuffer, out VisualStudioRazorParser parser)
public override bool TryGetParser(ITextBuffer textBuffer, out VisualStudioRazorParser parser)
{
if (textBuffer == null)
{

Просмотреть файл

@ -19,13 +19,11 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
private readonly ForegroundDispatcher _dispatcher;
private readonly TemplateEngineFactoryService _templateEngineFactoryService;
private readonly ICompletionBroker _completionBroker;
private readonly IEnumerable<IContextChangedListener> _parserContextChangedListeners;
private readonly ErrorReporter _errorReporter;
[ImportingConstructor]
public DefaultVisualStudioRazorParserFactory(
ICompletionBroker completionBroker,
[ImportMany(typeof(IContextChangedListener))] IEnumerable<IContextChangedListener> parserContextChangedListeners,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
{
if (completionBroker == null)
@ -33,18 +31,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
throw new ArgumentNullException(nameof(completionBroker));
}
if (parserContextChangedListeners == null)
{
throw new ArgumentNullException(nameof(parserContextChangedListeners));
}
if (workspace == null)
{
throw new ArgumentNullException(nameof(workspace));
}
_completionBroker = completionBroker;
_parserContextChangedListeners = parserContextChangedListeners;
_dispatcher = workspace.Services.GetRequiredService<ForegroundDispatcher>();
_errorReporter = workspace.Services.GetRequiredService<ErrorReporter>();
var razorLanguageServices = workspace.Services.GetLanguageServices(RazorLanguage.Name);
@ -65,8 +57,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
documentTracker,
_templateEngineFactoryService,
_errorReporter,
_completionBroker,
_parserContextChangedListeners);
_completionBroker);
return parser;
}
}

Просмотреть файл

@ -38,8 +38,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
documentTracker,
CreateTemplateEngineFactory(),
new DefaultErrorReporter(),
new TestCompletionBroker(),
Enumerable.Empty<IContextChangedListener>()))
new TestCompletionBroker()))
{
parser.DocumentTracker_ContextChanged(null, null);
var changed = new StringTextSnapshot("Foo @bap Daz");
@ -528,8 +527,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
documentTracker,
templateEngineFactory,
new DefaultErrorReporter(),
new TestCompletionBroker(),
Enumerable.Empty<IContextChangedListener>())
new TestCompletionBroker())
{
// We block idle work with the below reset events. Therefore, make tests fast and have the idle timer fire as soon as possible.
IdleDelay = TimeSpan.FromMilliseconds(1),

Просмотреть файл

@ -35,8 +35,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
Enumerable.Empty<IContextChangedListener>())
Mock.Of<ICompletionBroker>())
{
BlockBackgroundIdleWork = new ManualResetEventSlim(),
IdleDelay = TimeSpan.FromSeconds(5)
@ -66,8 +65,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
Enumerable.Empty<IContextChangedListener>())
Mock.Of<ICompletionBroker>())
{
BlockBackgroundIdleWork = new ManualResetEventSlim(),
IdleDelay = TimeSpan.FromSeconds(5)
@ -96,8 +94,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
Enumerable.Empty<IContextChangedListener>()))
Mock.Of<ICompletionBroker>()))
{
parser.StartParser();
@ -121,8 +118,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
documentTracker,
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
Enumerable.Empty<IContextChangedListener>()))
Mock.Of<ICompletionBroker>()))
{
// Act
parser.StartParser();
@ -133,31 +129,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
}
[ForegroundFact]
public void NotifyParserContextChanged_NotifiesListeners()
{
// Arrange
var listener1 = new Mock<IContextChangedListener>();
listener1.Setup(l => l.OnContextChanged(It.IsAny<VisualStudioRazorParser>()));
var listener2 = new Mock<IContextChangedListener>();
listener2.Setup(l => l.OnContextChanged(It.IsAny<VisualStudioRazorParser>()));
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
new[] { listener1.Object, listener2.Object }))
{
// Act
parser.NotifyParserContextChanged();
// Assert
listener1.Verify();
listener2.Verify();
}
}
[ForegroundFact]
public void TryReinitializeParser_ReturnsTrue_IfProjectIsSupported()
{
@ -167,8 +138,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(isSupportedProject: true),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
Enumerable.Empty<IContextChangedListener>()))
Mock.Of<ICompletionBroker>()))
{
// Act
var result = parser.TryReinitializeParser();
@ -187,8 +157,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(isSupportedProject: false),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>(),
Enumerable.Empty<IContextChangedListener>()))
Mock.Of<ICompletionBroker>()))
{
// Act
var result = parser.TryReinitializeParser();