From cf141cf11930b34ef0caa936026b071eaa6391cc Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 19 Sep 2017 12:30:58 -0700 Subject: [PATCH] Create new template engine when version changes --- .../DefaultVisualStudioDocumentTracker.cs | 50 +++++++++++++++++++ .../Legacy/RazorEditorParser.cs | 33 ++++++++---- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultVisualStudioDocumentTracker.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultVisualStudioDocumentTracker.cs index 3bdd04a3e4..9a97af28a6 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultVisualStudioDocumentTracker.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/Editor/DefaultVisualStudioDocumentTracker.cs @@ -3,6 +3,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -117,6 +121,52 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor { _project = project; + // Hack: When the context changes we want to replace the template engine held by the parser. + // This code isn't super well factored now - it's intended to be limited to one spot until + // we have time to a proper redesign. + + if (TextBuffer.Properties.TryGetProperty(typeof(RazorEditorParser), out RazorEditorParser legacyParser) && + legacyParser.TemplateEngine != null && + _projectPath != null) + { + var factory = _workspace.Services.GetLanguageServices(RazorLanguage.Name).GetRequiredService(); + + var existingEngine = legacyParser.TemplateEngine; + var projectDirectory = Path.GetDirectoryName(_projectPath); + var templateEngine = factory.Create(projectDirectory, builder => + { + var existingVSParserOptions = existingEngine.Engine.Features.FirstOrDefault( + feature => string.Equals( + feature.GetType().Name, + "VisualStudioParserOptionsFeature", + StringComparison.Ordinal)); + + if (existingVSParserOptions == null) + { + Debug.Fail("The VS Parser options should have been set."); + } + else + { + builder.Features.Add(existingVSParserOptions); + } + + var existingTagHelperFeature = existingEngine.Engine.Features + .OfType() + .FirstOrDefault(); + + if (existingTagHelperFeature == null) + { + Debug.Fail("The VS TagHelperFeature should have been set."); + } + else + { + builder.Features.Add(existingTagHelperFeature); + } + }); + + legacyParser.TemplateEngine = templateEngine; + } + var handler = ContextChanged; if (handler != null) { diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/Legacy/RazorEditorParser.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/Legacy/RazorEditorParser.cs index 0caebb1f68..edb369bc1a 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/Legacy/RazorEditorParser.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/Legacy/RazorEditorParser.cs @@ -15,6 +15,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor { public class RazorEditorParser : IDisposable { + private RazorTemplateEngine _templateEngine; + private AspNetCore.Razor.Language.Legacy.Span _lastChangeOwner; private AspNetCore.Razor.Language.Legacy.Span _lastAutoCompleteSpan; private BackgroundParser _parser; @@ -41,7 +43,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor TemplateEngine = templateEngine; FilePath = filePath; - _parser = new BackgroundParser(templateEngine, filePath); + _parser = new BackgroundParser(this, filePath); _parser.ResultsReady += (sender, args) => OnDocumentParseComplete(args); _parser.Start(); } @@ -51,7 +53,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor /// public event EventHandler DocumentParseComplete; - public RazorTemplateEngine TemplateEngine { get; } + public RazorTemplateEngine TemplateEngine + { + get => _templateEngine; + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _templateEngine = value; + } + } public string FilePath { get; } @@ -205,10 +219,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor private MainThreadState _main; private BackgroundThread _bg; - public BackgroundParser(RazorTemplateEngine templateEngine, string filePath) + public BackgroundParser(RazorEditorParser parser, string filePath) { _main = new MainThreadState(filePath); - _bg = new BackgroundThread(_main, templateEngine, filePath); + _bg = new BackgroundThread(_main, parser, filePath); _main.ResultsReady += (sender, args) => OnResultsReady(args); } @@ -454,17 +468,17 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor private MainThreadState _main; private Thread _backgroundThread; private CancellationToken _shutdownToken; - private RazorTemplateEngine _templateEngine; + private RazorEditorParser _parser; private string _filePath; private RazorSyntaxTree _currentSyntaxTree; private IList _previouslyDiscarded = new List(); - public BackgroundThread(MainThreadState main, RazorTemplateEngine templateEngine, string fileName) + public BackgroundThread(MainThreadState main, RazorEditorParser parser, string fileName) { // Run on MAIN thread! _main = main; _shutdownToken = _main.CancelToken; - _templateEngine = templateEngine; + _parser = parser; _filePath = fileName; _backgroundThread = new Thread(WorkerLoop); @@ -567,12 +581,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor { EnsureOnThread(); + var templateEngine = _parser.TemplateEngine; var sourceDocument = new TextSnapshotSourceDocument(snapshot, _filePath); - var imports = _templateEngine.GetImports(_filePath); + var imports = templateEngine.GetImports(_filePath); var codeDocument = RazorCodeDocument.Create(sourceDocument, imports); - _templateEngine.GenerateCode(codeDocument); + templateEngine.GenerateCode(codeDocument); return codeDocument; } }