提交 b0799619 编写于 作者: H HeeJae Chang 提交者: Sam Harwell

Support document-specific services with IDocumentService

上级 0bcb70c3
......@@ -32,6 +32,7 @@ public class TestHostDocument
private readonly SourceCodeKind _sourceCodeKind;
private readonly string _filePath;
private readonly IReadOnlyList<string> _folders;
private readonly IDocumentServiceProvider _documentServiceProvider;
public DocumentId Id
{
......@@ -101,7 +102,8 @@ public bool IsGenerated
IDictionary<string, ImmutableArray<TextSpan>> spans,
SourceCodeKind sourceCodeKind = SourceCodeKind.Regular,
IReadOnlyList<string> folders = null,
bool isLinkFile = false)
bool isLinkFile = false,
IDocumentServiceProvider documentServiceProvider = null)
{
Contract.ThrowIfNull(textBuffer);
Contract.ThrowIfNull(filePath);
......@@ -117,6 +119,7 @@ public bool IsGenerated
this.CursorPosition = cursorPosition;
_sourceCodeKind = sourceCodeKind;
this.IsLinkFile = isLinkFile;
_documentServiceProvider = documentServiceProvider;
this.SelectedSpans = new List<TextSpan>();
if (spans.ContainsKey(string.Empty))
......@@ -281,7 +284,7 @@ internal void CloseTextView()
public DocumentInfo ToDocumentInfo()
{
return DocumentInfo.Create(this.Id, this.Name, this.Folders, this.SourceCodeKind, loader: this.Loader, filePath: this.FilePath, isGenerated: this.IsGenerated);
return DocumentInfo.Create(this.Id, this.Name, this.Folders, this.SourceCodeKind, loader: this.Loader, filePath: this.FilePath, isGenerated: this.IsGenerated, _documentServiceProvider);
}
}
}
......@@ -71,12 +71,13 @@ public static TestWorkspace Create(string xmlDefinition, bool completed = true,
return Create(workspaceElement, completed, openDocuments, exportProvider, workspaceKind);
}
public static TestWorkspace Create(
internal static TestWorkspace Create(
XElement workspaceElement,
bool completed = true,
bool openDocuments = true,
ExportProvider exportProvider = null,
string workspaceKind = null)
string workspaceKind = null,
IDocumentServiceProvider documentServiceProvider = null)
{
if (workspaceElement.Name != WorkspaceElementName)
{
......@@ -103,6 +104,7 @@ public static TestWorkspace Create(string xmlDefinition, bool completed = true,
workspace,
documentElementToFilePath,
filePathToTextBufferMap,
documentServiceProvider,
ref projectIdentifier,
ref documentIdentifier);
Assert.False(projectNameToTestHostProject.ContainsKey(project.Name), $"The workspace XML already contains a project with name {project.Name}");
......@@ -255,6 +257,7 @@ public static TestWorkspace Create(string xmlDefinition, bool completed = true,
TestWorkspace workspace,
Dictionary<XElement, string> documentElementToFilePath,
Dictionary<string, ITextBuffer> filePathToTextBufferMap,
IDocumentServiceProvider documentServiceProvider,
ref int projectId,
ref int documentId)
{
......@@ -303,6 +306,7 @@ public static TestWorkspace Create(string xmlDefinition, bool completed = true,
exportProvider,
languageServices,
filePathToTextBufferMap,
documentServiceProvider,
ref documentId);
documents.Add(document);
......@@ -584,6 +588,7 @@ private static CompilationOptions CreateCompilationOptions(TestWorkspace workspa
ExportProvider exportProvider,
HostLanguageServices languageServiceProvider,
Dictionary<string, ITextBuffer> filePathToTextBufferMap,
IDocumentServiceProvider documentServiceProvider,
ref int documentId)
{
string markupCode;
......@@ -674,7 +679,8 @@ private static CompilationOptions CreateCompilationOptions(TestWorkspace workspa
filePathToTextBufferMap.Add(filePath, textBuffer);
}
return new TestHostDocument(exportProvider, languageServiceProvider, textBuffer, filePath, cursorPosition, spans, codeKind, folders, isLinkFile);
return new TestHostDocument(
exportProvider, languageServiceProvider, textBuffer, filePath, cursorPosition, spans, codeKind, folders, isLinkFile, documentServiceProvider);
}
private static string GetFilePath(
......
......@@ -5,6 +5,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Roslyn.Utilities;
......@@ -431,9 +432,14 @@ public void AddSourceFile(string fullPath, SourceCodeKind sourceCodeKind = Sourc
_sourceFiles.AddFile(fullPath, sourceCodeKind, folders);
}
public DocumentId AddSourceTextContainer(SourceTextContainer textContainer, string fullPath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular, ImmutableArray<string> folders = default)
public DocumentId AddSourceTextContainer(
SourceTextContainer textContainer,
string fullPath,
SourceCodeKind sourceCodeKind = SourceCodeKind.Regular,
ImmutableArray<string> folders = default,
IDocumentServiceProvider documentServiceProvider = null)
{
return _sourceFiles.AddTextContainer(textContainer, fullPath, sourceCodeKind, folders);
return _sourceFiles.AddTextContainer(textContainer, fullPath, sourceCodeKind, folders, documentServiceProvider);
}
public bool ContainsSourceFile(string fullPath)
......@@ -902,7 +908,7 @@ public DocumentId AddFile(string fullPath, SourceCodeKind sourceCodeKind, Immuta
return documentId;
}
public DocumentId AddTextContainer(SourceTextContainer textContainer, string fullPath, SourceCodeKind sourceCodeKind, ImmutableArray<string> folders)
public DocumentId AddTextContainer(SourceTextContainer textContainer, string fullPath, SourceCodeKind sourceCodeKind, ImmutableArray<string> folders, IDocumentServiceProvider documentServiceProvider)
{
if (textContainer == null)
{
......@@ -917,7 +923,9 @@ public DocumentId AddTextContainer(SourceTextContainer textContainer, string ful
folders: folders.IsDefault ? null : (IEnumerable<string>)folders,
sourceCodeKind: sourceCodeKind,
loader: textLoader,
filePath: fullPath);
filePath: fullPath,
isGenerated: false,
documentServiceProvider: documentServiceProvider);
lock (_project._gate)
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Host
{
/// <summary>
/// Empty interface just to mark document services.
/// </summary>
internal interface IDocumentService
{
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Host
{
internal interface IDocumentServiceProvider
{
/// <summary>
/// Gets a document specific service provided by the host identified by the service type.
/// If the host does not provide the service, this method returns null.
/// </summary>
TService GetService<TService>() where TService : class, IDocumentService;
}
}
// 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 Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// <see cref="IDocumentServiceProvider"/> for regular C#/VB files.
/// </summary>
internal sealed class DefaultTextDocumentServiceProvider : IDocumentServiceProvider
{
public static readonly DefaultTextDocumentServiceProvider Instance = new DefaultTextDocumentServiceProvider();
private DefaultTextDocumentServiceProvider() { }
public TService GetService<TService>() where TService : class, IDocumentService
{
return default;
}
}
}
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Serialization;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
......@@ -53,13 +54,19 @@ public sealed class DocumentInfo
/// </summary>
public TextLoader TextLoader { get; }
/// <summary>
/// A <see cref="IDocumentServiceProvider"/> associated with this document
/// </summary>
internal IDocumentServiceProvider DocumentServiceProvider { get; }
/// <summary>
/// Create a new instance of a <see cref="DocumentInfo"/>.
/// </summary>
internal DocumentInfo(DocumentAttributes attributes, TextLoader loader)
internal DocumentInfo(DocumentAttributes attributes, TextLoader loader, IDocumentServiceProvider documentServiceProvider)
{
Attributes = attributes;
TextLoader = loader;
DocumentServiceProvider = documentServiceProvider;
}
public static DocumentInfo Create(
......@@ -71,22 +78,39 @@ internal DocumentInfo(DocumentAttributes attributes, TextLoader loader)
string filePath = null,
bool isGenerated = false)
{
return new DocumentInfo(new DocumentAttributes(id, name, folders, sourceCodeKind, filePath, isGenerated), loader);
return Create(id, name, folders, sourceCodeKind, loader, filePath, isGenerated, documentServiceProvider: null);
}
internal static DocumentInfo Create(
DocumentId id,
string name,
IEnumerable<string> folders,
SourceCodeKind sourceCodeKind,
TextLoader loader,
string filePath,
bool isGenerated,
IDocumentServiceProvider documentServiceProvider)
{
return new DocumentInfo(new DocumentAttributes(id, name, folders, sourceCodeKind, filePath, isGenerated), loader, documentServiceProvider);
}
private DocumentInfo With(
DocumentAttributes attributes = null,
Optional<TextLoader> loader = default)
Optional<TextLoader> loader = default,
Optional<IDocumentServiceProvider> documentServiceProvider = default)
{
var newAttributes = attributes ?? Attributes;
var newLoader = loader.HasValue ? loader.Value : TextLoader;
var newDocumentServiceProvider = documentServiceProvider.HasValue ? documentServiceProvider.Value : DocumentServiceProvider;
if (newAttributes == Attributes && newLoader == TextLoader)
if (newAttributes == Attributes &&
newLoader == TextLoader &&
newDocumentServiceProvider == DocumentServiceProvider)
{
return this;
}
return new DocumentInfo(newAttributes, newLoader);
return new DocumentInfo(newAttributes, newLoader, newDocumentServiceProvider);
}
public DocumentInfo WithId(DocumentId id)
......
......@@ -28,13 +28,14 @@ internal partial class DocumentState : TextDocumentState
private DocumentState(
HostLanguageServices languageServices,
SolutionServices solutionServices,
IDocumentServiceProvider documentServiceProvider,
DocumentInfo.DocumentAttributes attributes,
ParseOptions options,
SourceText sourceTextOpt,
ValueSource<TextAndVersion> textSource,
ValueSource<TreeAndVersion> treeSource,
ValueSource<DocumentStateChecksums> lazyChecksums)
: base(solutionServices, attributes, sourceTextOpt, textSource, lazyChecksums)
: base(solutionServices, documentServiceProvider, attributes, sourceTextOpt, textSource, lazyChecksums)
{
_languageServices = languageServices;
_options = options;
......@@ -75,6 +76,7 @@ internal bool SupportsSyntaxTree
return new DocumentState(
languageServices: language,
documentServiceProvider: info.DocumentServiceProvider,
solutionServices: services,
attributes: info.Attributes,
options: options,
......@@ -332,6 +334,7 @@ private DocumentState SetParseOptions(ParseOptions options)
return new DocumentState(
this.LanguageServices,
this.solutionServices,
this.Services,
this.Attributes.With(sourceCodeKind: options.Kind),
options,
this.sourceTextOpt,
......@@ -355,6 +358,7 @@ public DocumentState UpdateName(string name)
return new DocumentState(
_languageServices,
this.solutionServices,
this.Services,
this.Attributes.With(name: name),
_options,
this.sourceTextOpt,
......@@ -368,6 +372,7 @@ public DocumentState UpdateFolders(IList<string> folders)
return new DocumentState(
_languageServices,
this.solutionServices,
this.Services,
this.Attributes.With(folders: folders),
_options,
this.sourceTextOpt,
......@@ -381,6 +386,7 @@ public DocumentState UpdateFilePath(string filePath)
return new DocumentState(
_languageServices,
this.solutionServices,
this.Services,
this.Attributes.With(filePath: filePath),
_options,
this.sourceTextOpt,
......@@ -428,6 +434,7 @@ public new DocumentState UpdateText(TextAndVersion newTextAndVersion, Preservati
return new DocumentState(
this.LanguageServices,
this.solutionServices,
this.Services,
this.Attributes,
_options,
sourceTextOpt: null,
......@@ -469,6 +476,7 @@ internal DocumentState UpdateText(TextLoader loader, SourceText textOpt, Preserv
return new DocumentState(
this.LanguageServices,
this.solutionServices,
this.Services,
this.Attributes,
_options,
sourceTextOpt: textOpt,
......@@ -511,6 +519,7 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode)
return new DocumentState(
this.LanguageServices,
this.solutionServices,
this.Services,
this.Attributes,
_options,
sourceTextOpt: null,
......
......@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
......@@ -51,6 +52,11 @@ internal TextDocument(Project project, TextDocumentState state)
/// </summary>
public IReadOnlyList<string> Folders => State.Folders;
/// <summary>
/// A <see cref="IDocumentServiceProvider"/> associated with this document
/// </summary>
internal IDocumentServiceProvider Services => State.Services;
/// <summary>
/// Get the current text for the document if it is already loaded and available.
/// </summary>
......
......@@ -39,6 +39,7 @@ internal partial class TextDocumentState
protected TextDocumentState(
SolutionServices solutionServices,
IDocumentServiceProvider documentServiceProvider,
DocumentInfo.DocumentAttributes attributes,
SourceText sourceTextOpt,
ValueSource<TextAndVersion> textAndVersionSource,
......@@ -49,6 +50,7 @@ internal partial class TextDocumentState
this.textAndVersionSource = textAndVersionSource;
Attributes = attributes;
Services = documentServiceProvider ?? DefaultTextDocumentServiceProvider.Instance;
// for now, let it re-calculate if anything changed.
// TODO: optimize this so that we only re-calcuate checksums that are actually changed
......@@ -57,6 +59,11 @@ internal partial class TextDocumentState
public DocumentInfo.DocumentAttributes Attributes { get; }
/// <summary>
/// A <see cref="IDocumentServiceProvider"/> associated with this document
/// </summary>
public IDocumentServiceProvider Services { get; }
public DocumentId Id
{
get { return Attributes.Id; }
......@@ -85,6 +92,7 @@ public static TextDocumentState Create(DocumentInfo info, SolutionServices servi
return new TextDocumentState(
solutionServices: services,
documentServiceProvider: info.DocumentServiceProvider,
attributes: info.Attributes,
sourceTextOpt: null,
textAndVersionSource: textSource,
......@@ -320,6 +328,7 @@ public TextDocumentState UpdateText(TextAndVersion newTextAndVersion, Preservati
return new TextDocumentState(
this.solutionServices,
this.Services,
this.Attributes,
sourceTextOpt: null,
textAndVersionSource: newTextSource,
......@@ -354,6 +363,7 @@ public TextDocumentState UpdateText(TextLoader loader, PreservationMode mode)
return new TextDocumentState(
this.solutionServices,
this.Services,
this.Attributes,
sourceTextOpt: null,
textAndVersionSource: newTextSource,
......
......@@ -1384,7 +1384,9 @@ protected virtual void ApplyProjectChanges(ProjectChanges projectChanges)
if (newDoc.HasInfoChanged(oldDoc))
{
// ApplyDocumentInfoChanged ignores the loader information, so we can pass null for it
ApplyDocumentInfoChanged(documentId, new DocumentInfo(newDoc.State.Attributes, loader: null));
ApplyDocumentInfoChanged(
documentId,
new DocumentInfo(newDoc.State.Attributes, loader: null, documentServiceProvider: newDoc.State.Services));
}
// update text if changed
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册