From 52b176956c3971035e5579a0162db1ff1a75b130 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 13 Jan 2016 10:59:09 -0800 Subject: [PATCH] Fixes #1003 MissingMethodException thrown on Django solution load Updates Django's completions and classifier to work with the public API changes made in VS 2015 U1. --- .../Intellisense/DjangoCompletionSource.cs | 11 ++- .../TemplateParsing/TemplateClassifier.cs | 84 +++++++++++++------ .../TemplateParsing/TemplateClassifierBase.cs | 2 +- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/Python/Product/Django/Intellisense/DjangoCompletionSource.cs b/Python/Product/Django/Intellisense/DjangoCompletionSource.cs index ae81cd4b49..c2151cbc57 100644 --- a/Python/Product/Django/Intellisense/DjangoCompletionSource.cs +++ b/Python/Product/Django/Intellisense/DjangoCompletionSource.cs @@ -21,6 +21,7 @@ using Microsoft.PythonTools.Intellisense; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Projection; #if DEV14_OR_LATER using Microsoft.Html.Editor.Document; @@ -37,13 +38,17 @@ public DjangoCompletionSource(IGlyphService glyphService, DjangoAnalyzer analyze } public override void AugmentCompletionSession(ICompletionSession session, IList completionSets) { - var doc = HtmlEditorDocument.FromTextBuffer(_buffer); + var doc = TemplateClassifier.HtmlEditorDocumentFromTextBuffer(_buffer); if (doc == null) { return; } - doc.HtmlEditorTree.EnsureTreeReady(); + var tree = doc.HtmlEditorTree; + if (tree == null) { + return; + } + tree.EnsureTreeReady(); - var primarySnapshot = doc.PrimaryView.TextSnapshot; + var primarySnapshot = tree.TextSnapshot; var nullableTriggerPoint = session.GetTriggerPoint(primarySnapshot); if (!nullableTriggerPoint.HasValue) { return; diff --git a/Python/Product/Django/TemplateParsing/TemplateClassifier.cs b/Python/Product/Django/TemplateParsing/TemplateClassifier.cs index d63e363c1e..0324ba8114 100644 --- a/Python/Product/Django/TemplateParsing/TemplateClassifier.cs +++ b/Python/Product/Django/TemplateParsing/TemplateClassifier.cs @@ -39,10 +39,28 @@ public TemplateClassifier(TemplateClassifierProviderBase provider, ITextBuffer t public override event EventHandler ClassificationChanged; + internal static HtmlEditorDocument HtmlEditorDocumentFromTextBuffer(ITextBuffer buffer) { + var doc = HtmlEditorDocument.FromTextBuffer(buffer); +#if DEV14_OR_LATER + if (doc == null) { + var projBuffer = buffer as IProjectionBuffer; + if (projBuffer != null) { + foreach (var b in projBuffer.SourceBuffers) { + if (b.ContentType.IsOfType(TemplateHtmlContentType.ContentTypeName) && + (doc = HtmlEditorDocument.TryFromTextBuffer(b)) != null) { + return doc; + } + } + } + } +#endif + return doc; + } + public override IList GetClassificationSpans(SnapshotSpan span) { var spans = new List(); - var htmlDoc = HtmlEditorDocument.TryFromTextBuffer(span.Snapshot.TextBuffer); + var htmlDoc = HtmlEditorDocumentFromTextBuffer(span.Snapshot.TextBuffer); if (htmlDoc == null) { return spans; } @@ -64,35 +82,49 @@ public TemplateClassifier(TemplateClassifierProviderBase provider, ITextBuffer t return spans; } - var projSnapshot = _htmlDoc.PrimaryView.TextSnapshot as IProjectionSnapshot; - if (projSnapshot == null) { - return spans; - } - - var primarySpans = projSnapshot.MapFromSourceSnapshot(span); - foreach (var primarySpan in primarySpans) { - var index = _htmlDoc.HtmlEditorTree.ArtifactCollection.GetItemContaining(primarySpan.Start); - if (index < 0) { - continue; - } - - var artifact = _htmlDoc.HtmlEditorTree.ArtifactCollection[index] as TemplateArtifact; - if (artifact == null) { - continue; + // The provided span may be in a projection snapshot, so we need to + // map back to the source snapshot to find the correct + // classification. If projSnapshot is null, we are already in the + // correct snapshot. + var projSnapshot = span.Snapshot as IProjectionSnapshot; + var sourceSnapshot = span.Snapshot; + + var sourceStartIndex = span.Start.Position; + if (projSnapshot != null) { + var pt = projSnapshot.MapToSourceSnapshot(sourceStartIndex); + sourceStartIndex = pt.Position; + sourceSnapshot = pt.Snapshot; + if (HtmlEditorDocument.TryFromTextBuffer(sourceSnapshot.TextBuffer) != _htmlDoc) { + return spans; } + } - var artifactStart = projSnapshot.MapToSourceSnapshot(artifact.InnerRange.Start); - if (artifactStart.Snapshot != span.Snapshot) { - continue; - } + var index = _htmlDoc.HtmlEditorTree.ArtifactCollection.GetItemContaining(sourceStartIndex); + if (index < 0) { + return spans; + } - var artifactText = _htmlDoc.HtmlEditorTree.ParseTree.Text.GetText(artifact.InnerRange); - artifact.Parse(artifactText); + var artifact = _htmlDoc.HtmlEditorTree.ArtifactCollection[index] as TemplateArtifact; + if (artifact == null) { + return spans; + } - var classifications = artifact.GetClassifications(); - foreach (var classification in classifications) { - var classificationSpan = ToClassificationSpan(classification, span.Snapshot, artifactStart.Position); - spans.Add(classificationSpan); + int artifactStart = artifact.InnerRange.Start; + var artifactText = _htmlDoc.HtmlEditorTree.ParseTree.Text.GetText(artifact.InnerRange); + artifact.Parse(artifactText); + + var classifications = artifact.GetClassifications(); + foreach (var classification in classifications) { + var cls = GetClassification(classification.Classification); + int clsStart = artifactStart + classification.Span.Start; + int clsLen = Math.Min(sourceSnapshot.Length - clsStart, classification.Span.Length); + var clsSpan = new SnapshotSpan(sourceSnapshot, clsStart, clsLen); + if (projSnapshot != null) { + foreach (var sp in projSnapshot.MapFromSourceSnapshot(clsSpan)) { + spans.Add(new ClassificationSpan(new SnapshotSpan(span.Snapshot, sp), cls)); + } + } else { + spans.Add(new ClassificationSpan(clsSpan, cls)); } } diff --git a/Python/Product/Django/TemplateParsing/TemplateClassifierBase.cs b/Python/Product/Django/TemplateParsing/TemplateClassifierBase.cs index 3af35d92c6..ff68571ef3 100644 --- a/Python/Product/Django/TemplateParsing/TemplateClassifierBase.cs +++ b/Python/Product/Django/TemplateParsing/TemplateClassifierBase.cs @@ -89,7 +89,7 @@ internal abstract class TemplateClassifierBase : IClassifier { ); } - private IClassificationType GetClassification(Classification classification) { + protected IClassificationType GetClassification(Classification classification) { switch (classification) { case Classification.None: return _classifierProvider._classType; case Classification.Keyword: return _classifierProvider._keywordType;