提交 70095aae 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #20048 from CyrusNajmabadi/textImageWork

Move over to the new ITextImage platform API.
......@@ -1260,4 +1260,4 @@ private struct ILMarker
public int AbsoluteOffset;
}
}
}
}
\ No newline at end of file
......@@ -24,14 +24,17 @@ public void GetBufferTextFromNonTextContainerThrows()
[Fact]
public void GetBufferTextFromTextContainerDoesNotThrow()
{
var textSnapshotMock = new Mock<VisualStudio.Text.ITextSnapshot>();
var textImageMock = new Mock<VisualStudio.Text.ITextImage>();
var textSnapshotMock = new Mock<VisualStudio.Text.ITextSnapshot2>();
var bufferMock = new Mock<VisualStudio.Text.ITextBuffer>();
textSnapshotMock.Setup(s => s.TextImage).Returns(textImageMock.Object);
bufferMock.SetupGet(x => x.CurrentSnapshot).Returns(textSnapshotMock.Object);
bufferMock.SetupGet(x => x.Properties).Returns(new VisualStudio.Utilities.PropertyCollection());
var textContainer = Microsoft.CodeAnalysis.Text.Extensions.TextBufferContainer.From(bufferMock.Object);
var textContainer = Text.Extensions.TextBufferContainer.From(bufferMock.Object);
Microsoft.CodeAnalysis.Text.Extensions.GetTextBuffer(textContainer);
Text.Extensions.GetTextBuffer(textContainer);
}
}
}
}
\ No newline at end of file
......@@ -109,7 +109,11 @@ private EditorTextFactoryService CreateMockTextFactoryService()
{
var text = reader.ReadToEnd();
var mockSnapshot = new Mock<ITextSnapshot>();
var mockImage = new Mock<ITextImage>();
mockImage.Setup(i => i.GetText(It.IsAny<Span>())).Returns(text);
var mockSnapshot = new Mock<ITextSnapshot2>();
mockSnapshot.Setup(s => s.TextImage).Returns(mockImage.Object);
mockSnapshot.Setup(s => s.GetText()).Returns(text);
var mockTextBuffer = new Mock<ITextBuffer>();
......
......@@ -10,7 +10,6 @@
using System.Threading;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
......@@ -29,8 +28,8 @@ private class SnapshotSourceText : SourceText
/// </summary>
internal sealed class ClosedSnapshotSourceText : SnapshotSourceText
{
public ClosedSnapshotSourceText(ITextSnapshot roslynSnapshot, Encoding encodingOpt)
: base(roslynSnapshot, encodingOpt, containerOpt: null)
public ClosedSnapshotSourceText(ITextImage textImage, Encoding encodingOpt)
: base(textImage, encodingOpt, containerOpt: null)
{
}
}
......@@ -38,9 +37,10 @@ public ClosedSnapshotSourceText(ITextSnapshot roslynSnapshot, Encoding encodingO
private static readonly Func<int, int, string> s_textLog = (v1, v2) => string.Format("FullRange : from {0} to {1}", v1, v2);
/// <summary>
/// The ITextSnapshot backing the SourceText instance
/// The <see cref="ITextImage"/> backing the SourceText instance
/// </summary>
protected readonly ITextSnapshot RoslynSnapshot;
public readonly ITextImage TextImage;
private readonly Encoding _encodingOpt;
private readonly TextBufferContainer _containerOpt;
private readonly int _reiteratedVersion;
......@@ -49,17 +49,17 @@ private SnapshotSourceText(ITextSnapshot editorSnapshot, Encoding encodingOpt)
{
Contract.ThrowIfNull(editorSnapshot);
this.RoslynSnapshot = TextBufferMapper.ToRoslyn(editorSnapshot);
this.TextImage = TextBufferMapper.RecordTextSnapshotAndGetImage(editorSnapshot);
_containerOpt = TextBufferContainer.From(editorSnapshot.TextBuffer);
_reiteratedVersion = editorSnapshot.Version.ReiteratedVersionNumber;
_encodingOpt = encodingOpt;
}
public SnapshotSourceText(ITextSnapshot roslynSnapshot, Encoding encodingOpt, TextBufferContainer containerOpt)
public SnapshotSourceText(ITextImage textImage, Encoding encodingOpt, TextBufferContainer containerOpt)
{
Contract.ThrowIfNull(roslynSnapshot);
Contract.ThrowIfNull(textImage);
this.RoslynSnapshot = roslynSnapshot;
this.TextImage = textImage;
_encodingOpt = encodingOpt;
_containerOpt = containerOpt;
}
......@@ -122,10 +122,8 @@ public override Encoding Encoding
get { return _encodingOpt; }
}
public ITextSnapshot EditorSnapshot
{
get { return TextBufferMapper.ToEditor(this.RoslynSnapshot); }
}
public ITextSnapshot TryFindEditorSnapshot()
=> TextBufferMapper.TryFindEditorSnapshot(this.TextImage);
protected static ITextBufferCloneService TextBufferFactory
{
......@@ -154,14 +152,14 @@ public override int Length
{
get
{
var res = this.RoslynSnapshot.Length;
var res = this.TextImage.Length;
return res;
}
}
public override char this[int position]
{
get { return this.RoslynSnapshot[position]; }
get { return this.TextImage[position]; }
}
#region Lines
......@@ -181,21 +179,21 @@ public LineInfo(SnapshotSourceText text)
public override int Count
{
get { return _text.RoslynSnapshot.LineCount; }
get { return _text.TextImage.LineCount; }
}
public override TextLine this[int index]
{
get
{
var line = _text.RoslynSnapshot.GetLineFromLineNumber(index);
var line = _text.TextImage.GetLineFromLineNumber(index);
return TextLine.FromSpan(_text, TextSpan.FromBounds(line.Start, line.End));
}
}
public override int IndexOf(int position)
{
return _text.RoslynSnapshot.GetLineNumberFromPosition(position);
return _text.TextImage.GetLineNumberFromPosition(position);
}
public override TextLine GetLineFromPosition(int position)
......@@ -205,7 +203,7 @@ public override TextLine GetLineFromPosition(int position)
public override LinePosition GetLinePosition(int position)
{
ITextSnapshotLine textLine = _text.RoslynSnapshot.GetLineFromPosition(position);
var textLine = _text.TextImage.GetLineFromPosition(position);
return new LinePosition(textLine.LineNumber, position - textLine.Start);
}
}
......@@ -213,13 +211,13 @@ public override LinePosition GetLinePosition(int position)
public override string ToString()
{
return this.RoslynSnapshot.GetText();
return this.TextImage.GetText();
}
public override string ToString(TextSpan textSpan)
{
var editorSpan = new Span(textSpan.Start, textSpan.Length);
var res = this.RoslynSnapshot.GetText(editorSpan);
var res = this.TextImage.GetText(editorSpan);
return res;
}
......@@ -244,7 +242,7 @@ public override SourceText WithChanges(IEnumerable<TextChange> changes)
}
// otherwise, create a new cloned snapshot
var buffer = factory.Clone(RoslynSnapshot.GetFullSpan());
var buffer = factory.Clone(TextImage);
var baseSnapshot = buffer.CurrentSnapshot;
// apply the change to the buffer
......@@ -258,7 +256,10 @@ public override SourceText WithChanges(IEnumerable<TextChange> changes)
edit.Apply();
}
return new ChangedSourceText(this, baseSnapshot, buffer.CurrentSnapshot);
return new ChangedSourceText(
baseText: this,
baseSnapshot: ((ITextSnapshot2)baseSnapshot).TextImage,
currentSnapshot: ((ITextSnapshot2)buffer.CurrentSnapshot).TextImage);
}
/// <summary>
......@@ -267,9 +268,9 @@ public override SourceText WithChanges(IEnumerable<TextChange> changes)
private class ChangedSourceText : SnapshotSourceText
{
private readonly SnapshotSourceText _baseText;
private readonly ITextSnapshot _baseSnapshot;
private readonly ITextImage _baseSnapshot;
public ChangedSourceText(SnapshotSourceText baseText, ITextSnapshot baseSnapshot, ITextSnapshot currentSnapshot)
public ChangedSourceText(SnapshotSourceText baseText, ITextImage baseSnapshot, ITextImage currentSnapshot)
: base(currentSnapshot, baseText.Encoding, containerOpt: null)
{
_baseText = baseText;
......@@ -294,18 +295,18 @@ public override IReadOnlyList<TextChangeRange> GetChangeRanges(SourceText oldTex
return new[] { new TextChangeRange(new TextSpan(0, oldText.Length), this.Length) };
}
return GetChangeRanges(_baseSnapshot, _baseSnapshot.Length, this.RoslynSnapshot);
return GetChangeRanges(_baseSnapshot, _baseSnapshot.Length, this.TextImage);
}
}
public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
{
this.RoslynSnapshot.CopyTo(sourceIndex, destination, destinationIndex, count);
this.TextImage.CopyTo(sourceIndex, destination, destinationIndex, count);
}
public override void Write(TextWriter textWriter, TextSpan span, CancellationToken cancellationToken)
{
this.RoslynSnapshot.Write(textWriter, span.ToSpan());
this.TextImage.Write(textWriter, span.ToSpan());
}
#region GetChangeRangesImplementation
......@@ -334,36 +335,44 @@ public override IReadOnlyList<TextChangeRange> GetChangeRanges(SourceText oldTex
}
}
var oldSnapshot = oldText.FindCorrespondingEditorTextSnapshot();
var newSnapshot = this.FindCorrespondingEditorTextSnapshot();
var oldSnapshot = oldText.TryFindCorrespondingEditorTextImage();
var newSnapshot = this.TryFindCorrespondingEditorTextImage();
return GetChangeRanges(oldSnapshot, oldText.Length, newSnapshot);
}
private IReadOnlyList<TextChangeRange> GetChangeRanges(ITextSnapshot oldSnapshot, int oldTextLength, ITextSnapshot newSnapshot)
private IReadOnlyList<TextChangeRange> GetChangeRanges(ITextImage oldImage, int oldTextLength, ITextImage newImage)
{
if (oldSnapshot == null ||
newSnapshot == null ||
oldSnapshot.TextBuffer != newSnapshot.TextBuffer)
if (oldImage == null ||
newImage == null ||
oldImage.Version.Identifier != newImage.Version.Identifier)
{
// Claim its all changed
Logger.Log(FunctionId.Workspace_SourceText_GetChangeRanges, "Invalid Snapshots");
return ImmutableArray.Create<TextChangeRange>(new TextChangeRange(new TextSpan(0, oldTextLength), this.Length));
return ImmutableArray.Create(new TextChangeRange(new TextSpan(0, oldTextLength), this.Length));
}
else if (oldSnapshot.Version.ReiteratedVersionNumber == newSnapshot.Version.ReiteratedVersionNumber)
else if (AreSameReiteratedVersion(oldImage, newImage))
{
// content of two snapshot must be same even if versions are different
return TextChangeRange.NoChanges;
}
else
{
return GetChangeRanges(oldSnapshot, newSnapshot, forward: oldSnapshot.Version.VersionNumber <= newSnapshot.Version.VersionNumber);
return GetChangeRanges(oldImage, newImage, forward: oldImage.Version.VersionNumber <= newImage.Version.VersionNumber);
}
}
private static bool AreSameReiteratedVersion(ITextImage oldImage, ITextImage newImage)
{
var oldSnapshot = TextBufferMapper.TryFindEditorSnapshot(oldImage);
var newSnapshot = TextBufferMapper.TryFindEditorSnapshot(newImage);
return oldSnapshot != null && newSnapshot != null && oldSnapshot.Version.ReiteratedVersionNumber == newSnapshot.Version.ReiteratedVersionNumber;
}
private static readonly Func<ITextChange, TextChangeRange> s_forwardTextChangeRange = c => CreateTextChangeRange(c, forward: true);
private static readonly Func<ITextChange, TextChangeRange> s_backwardTextChangeRange = c => CreateTextChangeRange(c, forward: false);
private IReadOnlyList<TextChangeRange> GetChangeRanges(ITextSnapshot snapshot1, ITextSnapshot snapshot2, bool forward)
private IReadOnlyList<TextChangeRange> GetChangeRanges(ITextImage snapshot1, ITextImage snapshot2, bool forward)
{
var oldSnapshot = forward ? snapshot1 : snapshot2;
var newSnapshot = forward ? snapshot2 : snapshot1;
......@@ -399,7 +408,7 @@ private IReadOnlyList<TextChangeRange> GetChangeRanges(ITextSnapshot snapshot1,
}
}
private TextChangeRange GetChangeRanges(ITextVersion oldVersion, ITextVersion newVersion, bool forward)
private TextChangeRange GetChangeRanges(ITextImageVersion oldVersion, ITextImageVersion newVersion, bool forward)
{
TextChangeRange? range = null;
var iterator = GetMultipleVersionTextChanges(oldVersion, newVersion, forward);
......@@ -412,7 +421,8 @@ private TextChangeRange GetChangeRanges(ITextVersion oldVersion, ITextVersion ne
return range.Value;
}
private static IEnumerable<IEnumerable<TextChangeRange>> GetMultipleVersionTextChanges(ITextVersion oldVersion, ITextVersion newVersion, bool forward)
private static IEnumerable<IEnumerable<TextChangeRange>> GetMultipleVersionTextChanges(
ITextImageVersion oldVersion, ITextImageVersion newVersion, bool forward)
{
for (var version = oldVersion; version != newVersion; version = version.Next)
{
......
// 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.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
......@@ -30,7 +29,7 @@ private TextBufferContainer(ITextBuffer editorBuffer, Encoding encoding)
Contract.ThrowIfNull(encoding);
_weakEditorBuffer = new WeakReference<ITextBuffer>(editorBuffer);
_currentText = new SnapshotSourceText(TextBufferMapper.ToRoslyn(editorBuffer.CurrentSnapshot), encoding, this);
_currentText = new SnapshotSourceText(TextBufferMapper.RecordTextSnapshotAndGetImage(editorBuffer.CurrentSnapshot), encoding, this);
}
/// <summary>
......@@ -54,13 +53,14 @@ private static TextBufferContainer CreateContainer(ITextBuffer editorBuffer)
return new TextBufferContainer(editorBuffer, editorBuffer.GetEncodingOrUTF8());
}
public ITextBuffer EditorTextBuffer { get { return _weakEditorBuffer.GetTarget(); } }
public ITextBuffer TryFindEditorTextBuffer()
=> _weakEditorBuffer.GetTarget();
public override SourceText CurrentText
{
get
{
var editorBuffer = this.EditorTextBuffer;
var editorBuffer = this.TryFindEditorTextBuffer();
return editorBuffer != null
? editorBuffer.CurrentSnapshot.AsText()
: _currentText;
......@@ -73,7 +73,7 @@ public override SourceText CurrentText
{
lock (_gate)
{
var textBuffer = this.EditorTextBuffer;
var textBuffer = this.TryFindEditorTextBuffer();
if (this.EtextChanged == null && textBuffer != null)
{
textBuffer.ChangedHighPriority += this.OnTextContentChanged;
......@@ -89,7 +89,7 @@ public override SourceText CurrentText
{
this.EtextChanged -= value;
var textBuffer = this.EditorTextBuffer;
var textBuffer = this.TryFindEditorTextBuffer();
if (this.EtextChanged == null && textBuffer != null)
{
textBuffer.ChangedHighPriority -= this.OnTextContentChanged;
......@@ -120,4 +120,4 @@ private void OnTextContentChanged(object sender, TextContentChangedEventArgs arg
public TextChangeEventArgs LastEventArgs { get; private set; }
}
}
}
}
\ No newline at end of file
......@@ -2,8 +2,6 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
......@@ -16,48 +14,32 @@ public static partial class Extensions
/// </summary>
private static class TextBufferMapper
{
private static readonly ConditionalWeakTable<ITextSnapshot, ITextSnapshot> s_editorToRoslynSnapshotMap = new ConditionalWeakTable<ITextSnapshot, ITextSnapshot>();
private static readonly ConditionalWeakTable<ITextSnapshot, WeakReference<ITextSnapshot>> s_roslynToEditorSnapshotMap = new ConditionalWeakTable<ITextSnapshot, WeakReference<ITextSnapshot>>();
private static readonly ConditionalWeakTable<ITextSnapshot, ITextSnapshot>.CreateValueCallback s_createSnapshotCallback = CreateSnapshot;
private static readonly ConditionalWeakTable<ITextImage, WeakReference<ITextSnapshot>> s_roslynToEditorSnapshotMap = new ConditionalWeakTable<ITextImage, WeakReference<ITextSnapshot>>();
public static ITextSnapshot ToRoslyn(ITextSnapshot editorSnapshot)
public static ITextImage RecordTextSnapshotAndGetImage(ITextSnapshot editorSnapshot)
{
Contract.ThrowIfNull(editorSnapshot);
var roslynSnapshot = s_editorToRoslynSnapshotMap.GetValue(editorSnapshot, s_createSnapshotCallback);
if (roslynSnapshot == null)
var textImage = ((ITextSnapshot2)editorSnapshot).TextImage;
Contract.ThrowIfNull(textImage);
// If we're already in the map, there's nothing to update. Do a quick check
// to avoid two allocations per call to RecordTextSnapshotAndGetImage.
if (!s_roslynToEditorSnapshotMap.TryGetValue(textImage, out var weakReference) ||
weakReference.GetTarget() != editorSnapshot)
{
return editorSnapshot;
// put reverse entry that won't hold onto anything
s_roslynToEditorSnapshotMap.GetValue(
textImage, _ => new WeakReference<ITextSnapshot>(editorSnapshot));
}
return roslynSnapshot;
}
private static ITextSnapshot CreateSnapshot(ITextSnapshot editorSnapshot)
{
var factory = TextBufferFactory;
// We might not have a factory if there is no primary workspace (for example, under the unit test harness,
// or in CodeSense where they are just using the parsers by themselves). In that case, just use the editor
// snapshot as-is.
//
// Creating a buffer off a given snapshot should be cheap, so it should be okay to create a dummy buffer here
// just to host the snapshot we want.
var roslynSnapshot = factory != null
? factory.Clone(editorSnapshot.GetFullSpan()).CurrentSnapshot
: editorSnapshot;
// put reverse entry that won't hold onto anything
var weakEditorSnapshot = new WeakReference<ITextSnapshot>(editorSnapshot);
s_roslynToEditorSnapshotMap.GetValue(roslynSnapshot, _ => weakEditorSnapshot);
return roslynSnapshot;
return textImage;
}
public static ITextSnapshot ToEditor(ITextSnapshot roslynSnapshot)
public static ITextSnapshot TryFindEditorSnapshot(ITextImage textImage)
{
Contract.ThrowIfNull(roslynSnapshot);
if (!s_roslynToEditorSnapshotMap.TryGetValue(roslynSnapshot, out var weakReference) ||
Contract.ThrowIfNull(textImage);
if (!s_roslynToEditorSnapshotMap.TryGetValue(textImage, out var weakReference) ||
!weakReference.TryGetTarget(out var editorSnapshot))
{
return null;
......@@ -82,4 +64,4 @@ private static ITextBufferCloneService TextBufferFactory
}
}
}
}
}
\ No newline at end of file
......@@ -18,7 +18,7 @@ public static ITextBuffer GetTextBuffer(this SourceTextContainer textContainer)
=> TryGetTextBuffer(textContainer) ?? throw new ArgumentException(TextEditorResources.textContainer_is_not_a_SourceTextContainer_that_was_created_from_an_ITextBuffer, nameof(textContainer));
public static ITextBuffer TryGetTextBuffer(this SourceTextContainer textContainer)
=> (textContainer as TextBufferContainer)?.EditorTextBuffer;
=> (textContainer as TextBufferContainer)?.TryFindEditorTextBuffer();
/// <summary>
/// Returns the ITextSnapshot behind this SourceText, or null if it wasn't created from one.
......@@ -28,7 +28,10 @@ public static ITextBuffer TryGetTextBuffer(this SourceTextContainer textContaine
/// </summary>
/// <returns>The underlying ITextSnapshot.</returns>
public static ITextSnapshot FindCorrespondingEditorTextSnapshot(this SourceText text)
=> (text as SnapshotSourceText)?.EditorSnapshot;
=> (text as SnapshotSourceText)?.TryFindEditorSnapshot();
internal static ITextImage TryFindCorrespondingEditorTextImage(this SourceText text)
=> (text as SnapshotSourceText)?.TextImage;
internal static TextLine AsTextLine(this ITextSnapshotLine line)
=> line.Snapshot.AsText().Lines[line.LineNumber];
......@@ -37,7 +40,7 @@ public static SourceText AsText(this ITextSnapshot textSnapshot)
=> SnapshotSourceText.From(textSnapshot);
internal static SourceText AsRoslynText(this ITextSnapshot textSnapshot, Encoding encoding)
=> new SnapshotSourceText.ClosedSnapshotSourceText(textSnapshot, encoding);
=> new SnapshotSourceText.ClosedSnapshotSourceText(((ITextSnapshot2)textSnapshot).TextImage, encoding);
/// <summary>
/// Gets the workspace corresponding to the text buffer.
......
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.Text;
......@@ -13,5 +8,6 @@ namespace Microsoft.CodeAnalysis.Text
internal interface ITextBufferCloneService : IWorkspaceService
{
ITextBuffer Clone(SnapshotSpan span);
ITextBuffer Clone(ITextImage textImage);
}
}
}
\ No newline at end of file
// 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 System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Text;
......@@ -23,7 +18,7 @@ internal class TextBufferCloneServiceFactory : IWorkspaceServiceFactory
ITextBufferFactoryService textBufferFactoryService,
IContentTypeRegistryService contentTypeRegistry)
{
_singleton = new TextBufferCloneService((ITextBufferFactoryService2)textBufferFactoryService, contentTypeRegistry.UnknownContentType);
_singleton = new TextBufferCloneService((ITextBufferFactoryService3)textBufferFactoryService, contentTypeRegistry.UnknownContentType);
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
......@@ -33,19 +28,20 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
private class TextBufferCloneService : ITextBufferCloneService
{
private readonly ITextBufferFactoryService2 _textBufferFactoryService;
private readonly ITextBufferFactoryService3 _textBufferFactoryService;
private readonly IContentType _unknownContentType;
public TextBufferCloneService(ITextBufferFactoryService2 textBufferFactoryService, IContentType unknownContentType)
public TextBufferCloneService(ITextBufferFactoryService3 textBufferFactoryService, IContentType unknownContentType)
{
_textBufferFactoryService = textBufferFactoryService;
_unknownContentType = unknownContentType;
}
public ITextBuffer Clone(SnapshotSpan span)
{
return _textBufferFactoryService.CreateTextBuffer(span, _unknownContentType);
}
=> _textBufferFactoryService.CreateTextBuffer(span, _unknownContentType);
public ITextBuffer Clone(ITextImage textImage)
=> _textBufferFactoryService.CreateTextBuffer(textImage, _unknownContentType);
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册