提交 4924d709 编写于 作者: S Sam Harwell

Place ITextBufferCloneService in ITextBuffer.Properties instead of separate...

Place ITextBufferCloneService in ITextBuffer.Properties instead of separate tracking in SnapshotSourceText
上级 9c28f4ad
......@@ -13,18 +13,20 @@
namespace Microsoft.CodeAnalysis.Editor.Implementation.Workspaces
{
[ExportWorkspaceService(typeof(ITextFactoryService), ServiceLayer.Editor), Shared]
internal class EditorTextFactoryService : ITextFactoryService
{
private readonly Workspace _workspace;
private readonly ITextBufferCloneService _textBufferCloneService;
private readonly ITextBufferFactoryService _textBufferFactory;
private readonly IContentType _unknownContentType;
[ImportingConstructor]
public EditorTextFactoryService(
Workspace workspace,
ITextBufferCloneService textBufferCloneService,
ITextBufferFactoryService textBufferFactoryService,
IContentTypeRegistryService contentTypeRegistryService)
{
_workspace = workspace;
_textBufferCloneService = textBufferCloneService;
_textBufferFactory = textBufferFactoryService;
_unknownContentType = contentTypeRegistryService.UnknownContentType;
}
......@@ -69,7 +71,7 @@ public SourceText CreateText(TextReader reader, Encoding encoding, CancellationT
var buffer = CreateTextBuffer(reader, cancellationToken);
// use the given encoding as it is.
return buffer.CurrentSnapshot.AsRoslynText(_workspace, encoding);
return buffer.CurrentSnapshot.AsRoslynText(_textBufferCloneService, encoding);
}
private ITextBuffer CreateTextBuffer(TextReader reader, CancellationToken cancellationToken = default)
......@@ -85,31 +87,7 @@ private SourceText CreateTextInternal(Stream stream, Encoding encoding, Cancella
using (var reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true))
{
var buffer = CreateTextBuffer(reader, cancellationToken);
return buffer.CurrentSnapshot.AsRoslynText(_workspace, reader.CurrentEncoding ?? Encoding.UTF8);
}
}
[ExportWorkspaceServiceFactory(typeof(ITextFactoryService), ServiceLayer.Editor), Shared]
private sealed class Factory : IWorkspaceServiceFactory
{
private readonly ITextBufferFactoryService _textBufferFactoryService;
private readonly IContentTypeRegistryService _contentTypeRegistryService;
[ImportingConstructor]
public Factory(
ITextBufferFactoryService textBufferFactoryService,
IContentTypeRegistryService contentTypeRegistryService)
{
_textBufferFactoryService = textBufferFactoryService;
_contentTypeRegistryService = contentTypeRegistryService;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new EditorTextFactoryService(
workspaceServices.Workspace,
_textBufferFactoryService,
_contentTypeRegistryService);
return buffer.CurrentSnapshot.AsRoslynText(_textBufferCloneService, reader.CurrentEncoding ?? Encoding.UTF8);
}
}
}
......
......@@ -33,7 +33,7 @@ public void GetBufferTextFromTextContainerDoesNotThrow()
bufferMock.SetupGet(x => x.CurrentSnapshot).Returns(textSnapshotMock.Object);
bufferMock.SetupGet(x => x.Properties).Returns(new VisualStudio.Utilities.PropertyCollection());
var textContainer = Text.Extensions.TextBufferContainer.From(workspace: null, bufferMock.Object);
var textContainer = Text.Extensions.TextBufferContainer.From(bufferMock.Object);
Text.Extensions.GetTextBuffer(textContainer);
}
......
// 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.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Implementation.Workspaces;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Utilities;
using Moq;
......@@ -21,108 +23,86 @@ public class TextFactoryTests
[Fact, WorkItem(1038018, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1038018"), WorkItem(1041792, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1041792")]
public void TestCreateTextFallsBackToSystemDefaultEncoding()
{
using (var workspace = new TestWorkspace())
{
TestCreateTextInferredEncoding(
workspace,
_nonUTF8StringBytes,
defaultEncoding: null,
expectedEncoding: Encoding.Default);
}
TestCreateTextInferredEncoding(
_nonUTF8StringBytes,
defaultEncoding: null,
expectedEncoding: Encoding.Default);
}
[Fact, WorkItem(1038018, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1038018")]
public void TestCreateTextFallsBackToUTF8Encoding()
{
using (var workspace = new TestWorkspace())
{
TestCreateTextInferredEncoding(
workspace,
new ASCIIEncoding().GetBytes("Test"),
defaultEncoding: null,
expectedEncoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true));
}
TestCreateTextInferredEncoding(
new ASCIIEncoding().GetBytes("Test"),
defaultEncoding: null,
expectedEncoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true));
}
[Fact, WorkItem(1038018, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1038018")]
public void TestCreateTextFallsBackToProvidedDefaultEncoding()
{
using (var workspace = new TestWorkspace())
{
TestCreateTextInferredEncoding(
workspace,
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes("Test"),
defaultEncoding: Encoding.GetEncoding(1254),
expectedEncoding: Encoding.GetEncoding(1254));
}
TestCreateTextInferredEncoding(
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes("Test"),
defaultEncoding: Encoding.GetEncoding(1254),
expectedEncoding: Encoding.GetEncoding(1254));
}
[Fact, WorkItem(1038018, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1038018")]
public void TestCreateTextUsesByteOrderMarkIfPresent()
{
using (var workspace = new TestWorkspace())
{
TestCreateTextInferredEncoding(
workspace,
Encoding.UTF8.GetPreamble().Concat(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes("Test")).ToArray(),
defaultEncoding: Encoding.GetEncoding(1254),
expectedEncoding: Encoding.UTF8);
}
TestCreateTextInferredEncoding(
Encoding.UTF8.GetPreamble().Concat(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes("Test")).ToArray(),
defaultEncoding: Encoding.GetEncoding(1254),
expectedEncoding: Encoding.UTF8);
}
[Fact]
public async Task TestCreateFromTemporaryStorage()
{
using (var workspace = new TestWorkspace())
{
var textFactory = CreateMockTextFactoryService(workspace);
var temporaryStorageService = new TemporaryStorageServiceFactory.TemporaryStorageService(textFactory);
var textFactory = CreateMockTextFactoryService();
var temporaryStorageService = new TemporaryStorageServiceFactory.TemporaryStorageService(textFactory);
var text = Text.SourceText.From("Hello, World!");
var text = Text.SourceText.From("Hello, World!");
// Create a temporary storage location
using (var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None))
{
// Write text into it
await temporaryStorage.WriteTextAsync(text);
// Create a temporary storage location
using (var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None))
{
// Write text into it
await temporaryStorage.WriteTextAsync(text);
// Read text back from it
var text2 = await temporaryStorage.ReadTextAsync();
// Read text back from it
var text2 = await temporaryStorage.ReadTextAsync();
Assert.NotSame(text, text2);
Assert.Equal(text.ToString(), text2.ToString());
Assert.Equal(text2.Encoding, null);
}
Assert.NotSame(text, text2);
Assert.Equal(text.ToString(), text2.ToString());
Assert.Equal(text2.Encoding, null);
}
}
[Fact]
public async Task TestCreateFromTemporaryStorageWithEncoding()
{
using (var workspace = new TestWorkspace())
{
var textFactory = CreateMockTextFactoryService(workspace);
var temporaryStorageService = new TemporaryStorageServiceFactory.TemporaryStorageService(textFactory);
var textFactory = CreateMockTextFactoryService();
var temporaryStorageService = new TemporaryStorageServiceFactory.TemporaryStorageService(textFactory);
var text = Text.SourceText.From("Hello, World!", Encoding.ASCII);
var text = Text.SourceText.From("Hello, World!", Encoding.ASCII);
// Create a temporary storage location
using (var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None))
{
// Write text into it
await temporaryStorage.WriteTextAsync(text);
// Create a temporary storage location
using (var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None))
{
// Write text into it
await temporaryStorage.WriteTextAsync(text);
// Read text back from it
var text2 = await temporaryStorage.ReadTextAsync();
// Read text back from it
var text2 = await temporaryStorage.ReadTextAsync();
Assert.NotSame(text, text2);
Assert.Equal(text.ToString(), text2.ToString());
Assert.Equal(text2.Encoding, Encoding.ASCII);
}
Assert.NotSame(text, text2);
Assert.Equal(text.ToString(), text2.ToString());
Assert.Equal(text2.Encoding, Encoding.ASCII);
}
}
private EditorTextFactoryService CreateMockTextFactoryService(Workspace workspace)
private EditorTextFactoryService CreateMockTextFactoryService()
{
var mockTextBufferFactoryService = new Mock<ITextBufferFactoryService>();
mockTextBufferFactoryService
......@@ -143,17 +123,24 @@ private EditorTextFactoryService CreateMockTextFactoryService(Workspace workspac
return mockTextBuffer.Object;
});
return new EditorTextFactoryService(workspace, mockTextBufferFactoryService.Object, new Mock<IContentTypeRegistryService>().Object);
return new EditorTextFactoryService(new FakeTextBufferCloneService(), mockTextBufferFactoryService.Object, new Mock<IContentTypeRegistryService>().Object);
}
private void TestCreateTextInferredEncoding(Workspace workspace, byte[] bytes, Encoding defaultEncoding, Encoding expectedEncoding)
private void TestCreateTextInferredEncoding(byte[] bytes, Encoding defaultEncoding, Encoding expectedEncoding)
{
var factory = CreateMockTextFactoryService(workspace);
var factory = CreateMockTextFactoryService();
using (var stream = new MemoryStream(bytes))
{
var text = factory.CreateText(stream, defaultEncoding);
Assert.Equal(expectedEncoding, text.Encoding);
}
}
private class FakeTextBufferCloneService : ITextBufferCloneService
{
public ITextBuffer Clone(SnapshotSpan span) => throw new NotImplementedException();
public ITextBuffer Clone(ITextImage textImage) => throw new NotImplementedException();
}
}
}
......@@ -24,36 +24,36 @@ private class SnapshotSourceText : SourceText
{
private static readonly Func<int, int, string> s_textLog = (v1, v2) => string.Format("FullRange : from {0} to {1}", v1, v2);
private readonly Workspace _workspace;
/// <summary>
/// The <see cref="ITextImage"/> backing the SourceText instance
/// </summary>
public readonly ITextImage TextImage;
private readonly ITextBufferCloneService _textBufferCloneServiceOpt;
private readonly Encoding _encodingOpt;
private readonly TextBufferContainer _containerOpt;
private SnapshotSourceText(Workspace workspace, ITextSnapshot editorSnapshot) :
this(workspace, editorSnapshot, TextBufferContainer.From(workspace, editorSnapshot.TextBuffer))
private SnapshotSourceText(ITextBufferCloneService textBufferCloneServiceOpt, ITextSnapshot editorSnapshot) :
this(textBufferCloneServiceOpt, editorSnapshot, TextBufferContainer.From(editorSnapshot.TextBuffer))
{
}
private SnapshotSourceText(Workspace workspace, ITextSnapshot editorSnapshot, TextBufferContainer container)
private SnapshotSourceText(ITextBufferCloneService textBufferCloneServiceOpt, ITextSnapshot editorSnapshot, TextBufferContainer container)
{
Contract.ThrowIfNull(editorSnapshot);
_workspace = workspace;
_textBufferCloneServiceOpt = textBufferCloneServiceOpt;
this.TextImage = RecordReverseMapAndGetImage(editorSnapshot);
_encodingOpt = editorSnapshot.TextBuffer.GetEncodingOrUTF8();
_containerOpt = container;
}
public SnapshotSourceText(Workspace workspace, ITextImage textImage, Encoding encodingOpt, TextBufferContainer containerOpt)
public SnapshotSourceText(ITextBufferCloneService textBufferCloneServiceOpt, ITextImage textImage, Encoding encodingOpt, TextBufferContainer containerOpt)
{
Contract.ThrowIfNull(textImage);
_workspace = workspace;
_textBufferCloneServiceOpt = textBufferCloneServiceOpt;
this.TextImage = textImage;
_encodingOpt = encodingOpt;
_containerOpt = containerOpt;
......@@ -70,9 +70,7 @@ public SnapshotSourceText(Workspace workspace, ITextImage textImage, Encoding en
/// </summary>
private static readonly ConditionalWeakTable<ITextImage, WeakReference<ITextSnapshot>> s_textImageToEditorSnapshotMap = new ConditionalWeakTable<ITextImage, WeakReference<ITextSnapshot>>();
internal Workspace Workspace => _workspace;
public static SourceText From(Workspace workspace, ITextSnapshot editorSnapshot)
public static SourceText From(ITextBufferCloneService textBufferCloneServiceOpt, ITextSnapshot editorSnapshot)
{
if (editorSnapshot == null)
{
......@@ -82,8 +80,8 @@ public static SourceText From(Workspace workspace, ITextSnapshot editorSnapshot)
if (!s_textSnapshotMap.TryGetValue(editorSnapshot, out var snapshot))
{
// Avoid capturing `workspace` on the fast path
var tempWorkspace = workspace;
snapshot = s_textSnapshotMap.GetValue(editorSnapshot, s => new SnapshotSourceText(tempWorkspace, s));
var tempTextBufferCloneServiceOpt = textBufferCloneServiceOpt;
snapshot = s_textSnapshotMap.GetValue(editorSnapshot, s => new SnapshotSourceText(tempTextBufferCloneServiceOpt, s));
}
return snapshot;
......@@ -92,7 +90,7 @@ public static SourceText From(Workspace workspace, ITextSnapshot editorSnapshot)
/// <summary>
/// This only exist to break circular dependency on creating buffer. nobody except extension itself should use it
/// </summary>
internal static SourceText From(Workspace workspace, ITextSnapshot editorSnapshot, TextBufferContainer container)
internal static SourceText From(ITextBufferCloneService textBufferCloneServiceOpt, ITextSnapshot editorSnapshot, TextBufferContainer container)
{
if (editorSnapshot == null)
{
......@@ -100,7 +98,7 @@ internal static SourceText From(Workspace workspace, ITextSnapshot editorSnapsho
}
Contract.ThrowIfFalse(editorSnapshot.TextBuffer == container.GetTextBuffer());
return s_textSnapshotMap.GetValue(editorSnapshot, s => new SnapshotSourceText(workspace, s, container));
return s_textSnapshotMap.GetValue(editorSnapshot, s => new SnapshotSourceText(textBufferCloneServiceOpt, s, container));
}
public override Encoding Encoding
......@@ -111,14 +109,6 @@ public override Encoding Encoding
public ITextSnapshot TryFindEditorSnapshot()
=> TryFindEditorSnapshot(this.TextImage);
protected ITextBufferCloneService TextBufferFactory
{
get
{
return _workspace?.Services.GetService<ITextBufferCloneService>();
}
}
public override SourceTextContainer Container
{
get
......@@ -213,7 +203,7 @@ public override SourceText WithChanges(IEnumerable<TextChange> changes)
}
// check whether we can use text buffer factory
var factory = TextBufferFactory;
var factory = _textBufferCloneServiceOpt;
if (factory == null)
{
// if we can't get the factory, use the default implementation
......@@ -236,7 +226,7 @@ public override SourceText WithChanges(IEnumerable<TextChange> changes)
}
return new ChangedSourceText(
workspace: _workspace,
textBufferCloneServiceOpt: _textBufferCloneServiceOpt,
baseText: this,
baseSnapshot: ((ITextSnapshot2)baseSnapshot).TextImage,
currentSnapshot: ((ITextSnapshot2)buffer.CurrentSnapshot).TextImage);
......@@ -282,8 +272,8 @@ private static ITextSnapshot TryFindEditorSnapshot(ITextImage textImage)
/// </summary>
internal sealed class ClosedSnapshotSourceText : SnapshotSourceText
{
public ClosedSnapshotSourceText(Workspace workspace, ITextImage textImage, Encoding encodingOpt)
: base(workspace, textImage, encodingOpt, containerOpt: null)
public ClosedSnapshotSourceText(ITextBufferCloneService textBufferCloneServiceOpt, ITextImage textImage, Encoding encodingOpt)
: base(textBufferCloneServiceOpt, textImage, encodingOpt, containerOpt: null)
{
}
}
......@@ -296,8 +286,8 @@ private class ChangedSourceText : SnapshotSourceText
private readonly SnapshotSourceText _baseText;
private readonly ITextImage _baseSnapshot;
public ChangedSourceText(Workspace workspace, SnapshotSourceText baseText, ITextImage baseSnapshot, ITextImage currentSnapshot)
: base(workspace, currentSnapshot, baseText.Encoding, containerOpt: null)
public ChangedSourceText(ITextBufferCloneService textBufferCloneServiceOpt, SnapshotSourceText baseText, ITextImage baseSnapshot, ITextImage currentSnapshot)
: base(textBufferCloneServiceOpt, currentSnapshot, baseText.Encoding, containerOpt: null)
{
_baseText = baseText;
_baseSnapshot = baseSnapshot;
......
......@@ -4,7 +4,6 @@
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
......@@ -19,49 +18,39 @@ internal class TextBufferContainer : SourceTextContainer
{
private readonly WeakReference<ITextBuffer> _weakEditorBuffer;
private readonly object _gate = new object();
private readonly ITextBufferCloneService _textBufferCloneServiceOpt;
private event EventHandler<TextChangeEventArgs> EtextChanged;
private SourceText _currentText;
private TextBufferContainer(Workspace workspace, ITextBuffer editorBuffer)
private TextBufferContainer(ITextBuffer editorBuffer)
{
Contract.ThrowIfNull(editorBuffer);
_weakEditorBuffer = new WeakReference<ITextBuffer>(editorBuffer);
_currentText = SnapshotSourceText.From(workspace, editorBuffer.CurrentSnapshot, this);
editorBuffer.Properties.TryGetProperty(typeof(ITextBufferCloneService), out _textBufferCloneServiceOpt);
_currentText = SnapshotSourceText.From(_textBufferCloneServiceOpt, editorBuffer.CurrentSnapshot, this);
}
/// <summary>
/// A weak map of all Editor ITextBuffers and their associated SourceTextContainer
/// </summary>
private static readonly ConditionalWeakTable<ITextBuffer, TextBufferContainer> s_textContainerMap = new ConditionalWeakTable<ITextBuffer, TextBufferContainer>();
private static readonly ConditionalWeakTable<ITextBuffer, TextBufferContainer>.CreateValueCallback s_createContainerWithoutWorkspaceCallback = CreateContainer;
private static readonly ConditionalWeakTable<ITextBuffer, TextBufferContainer>.CreateValueCallback s_createContainerCallback = CreateContainer;
public static TextBufferContainer From(Workspace workspace, ITextBuffer buffer)
public static TextBufferContainer From(ITextBuffer buffer)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (workspace is null)
{
return s_textContainerMap.GetValue(buffer, s_createContainerWithoutWorkspaceCallback);
}
if (!s_textContainerMap.TryGetValue(buffer, out var container))
{
// Avoid capturing 'workspace' on the fast path
var workspaceCopy = workspace;
container = s_textContainerMap.GetValue(buffer, key => new TextBufferContainer(workspace, key));
}
return container;
return s_textContainerMap.GetValue(buffer, s_createContainerCallback);
}
private static TextBufferContainer CreateContainer(ITextBuffer editorBuffer)
{
return new TextBufferContainer(workspace: null, editorBuffer);
return new TextBufferContainer(editorBuffer);
}
public ITextBuffer TryFindEditorTextBuffer()
......@@ -122,7 +111,7 @@ private void OnTextContentChanged(object sender, TextContentChangedEventArgs arg
// this should convert given editor snapshots to roslyn forked snapshots
var oldText = (SnapshotSourceText)args.Before.AsText();
var newText = SnapshotSourceText.From(oldText.Workspace, args.After);
var newText = SnapshotSourceText.From(_textBufferCloneServiceOpt, args.After);
_currentText = newText;
var changes = ImmutableArray.CreateRange(args.Changes.Select(c => new TextChangeRange(new TextSpan(c.OldSpan.Start, c.OldSpan.Length), c.NewLength)));
......
......@@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Text
public static partial class Extensions
{
public static SourceTextContainer AsTextContainer(this ITextBuffer buffer)
=> TextBufferContainer.From(workspace: null, buffer);
=> TextBufferContainer.From(buffer);
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));
......@@ -37,10 +37,10 @@ internal static TextLine AsTextLine(this ITextSnapshotLine line)
=> line.Snapshot.AsText().Lines[line.LineNumber];
public static SourceText AsText(this ITextSnapshot textSnapshot)
=> SnapshotSourceText.From(workspace: null, textSnapshot);
=> SnapshotSourceText.From(textBufferCloneServiceOpt: null, textSnapshot);
internal static SourceText AsRoslynText(this ITextSnapshot textSnapshot, Workspace workspace, Encoding encoding)
=> new SnapshotSourceText.ClosedSnapshotSourceText(workspace, ((ITextSnapshot2)textSnapshot).TextImage, encoding);
internal static SourceText AsRoslynText(this ITextSnapshot textSnapshot, ITextBufferCloneService textBufferCloneServiceOpt, Encoding encoding)
=> new SnapshotSourceText.ClosedSnapshotSourceText(textBufferCloneServiceOpt, ((ITextSnapshot2)textSnapshot).TextImage, encoding);
/// <summary>
/// Gets the workspace corresponding to the text buffer.
......
......@@ -16,9 +16,9 @@ internal class TextBufferCloneServiceFactory : IWorkspaceServiceFactory
[ImportingConstructor]
public TextBufferCloneServiceFactory(
ITextBufferFactoryService textBufferFactoryService,
IContentTypeRegistryService contentTypeRegistry)
IContentTypeRegistryService contentTypeRegistryService)
{
_singleton = new TextBufferCloneService((ITextBufferFactoryService3)textBufferFactoryService, contentTypeRegistry.UnknownContentType);
_singleton = new TextBufferCloneService((ITextBufferFactoryService3)textBufferFactoryService, contentTypeRegistryService);
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
......@@ -26,15 +26,17 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
return _singleton;
}
[Export(typeof(ITextBufferCloneService)), Shared]
private class TextBufferCloneService : ITextBufferCloneService
{
private readonly ITextBufferFactoryService3 _textBufferFactoryService;
private readonly IContentType _unknownContentType;
public TextBufferCloneService(ITextBufferFactoryService3 textBufferFactoryService, IContentType unknownContentType)
[ImportingConstructor]
public TextBufferCloneService(ITextBufferFactoryService3 textBufferFactoryService, IContentTypeRegistryService contentTypeRegistryService)
{
_textBufferFactoryService = textBufferFactoryService;
_unknownContentType = unknownContentType;
_unknownContentType = contentTypeRegistryService.UnknownContentType;
}
public ITextBuffer Clone(SnapshotSpan span)
......
......@@ -22,6 +22,7 @@
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
using VSLangProj;
using VSLangProj140;
......@@ -37,6 +38,9 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac
private static readonly IntPtr s_docDataExisting_Unknown = new IntPtr(-1);
private const string AppCodeFolderName = "App_Code";
private readonly ITextBufferFactoryService _textBufferFactoryService;
private readonly ITextBufferCloneService _textBufferCloneService;
// document worker coordinator
private ISolutionCrawlerRegistrationService _registrationService;
......@@ -58,6 +62,9 @@ public VisualStudioWorkspaceImpl(ExportProvider exportProvider)
MefV1HostServices.Create(exportProvider),
backgroundWork: WorkspaceBackgroundWork.ParseAndCompile)
{
_textBufferCloneService = exportProvider.GetExportedValue<ITextBufferCloneService>();
_textBufferFactoryService = exportProvider.GetExportedValue<ITextBufferFactoryService>();
_textBufferFactoryService.TextBufferCreated += AddTextBufferCloneServiceToBuffer;
exportProvider.GetExportedValue<PrimaryWorkspace>().Register(this);
}
......@@ -213,6 +220,11 @@ protected override bool CanApplyParseOptionChange(ParseOptions oldOptions, Parse
return newOptions == updated;
}
private void AddTextBufferCloneServiceToBuffer(object sender, TextBufferCreatedEventArgs e)
{
e.TextBuffer.Properties.AddProperty(typeof(ITextBufferCloneService), _textBufferCloneService);
}
public override bool CanApplyChange(ApplyChangesKind feature)
{
switch (feature)
......@@ -1081,6 +1093,11 @@ internal void StopSolutionCrawler()
protected override void Dispose(bool finalize)
{
if (!finalize)
{
_textBufferFactoryService.TextBufferCreated -= AddTextBufferCloneServiceToBuffer;
}
// workspace is going away. unregister this workspace from work coordinator
StopSolutionCrawler();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册