提交 ced272a5 编写于 作者: I Ivan Basov

extracting intellisense control services

上级 4b08340d
......@@ -5,7 +5,6 @@
using Microsoft.CodeAnalysis.ChangeSignature;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature
{
......@@ -25,7 +24,9 @@ AddedParameterResult IChangeSignatureOptionsService.GetAddedParameter(Document d
throw new System.NotImplementedException();
}
ChangeSignatureOptionsResult IChangeSignatureOptionsService.GetChangeSignatureOptions(ISymbol symbol, int insertPosition, ParameterConfiguration parameters, Document document, INotificationService notificationService)
ChangeSignatureOptionsResult IChangeSignatureOptionsService.GetChangeSignatureOptions(
ISymbol symbol, int insertPosition, ParameterConfiguration parameters,
Document document)
{
var list = parameters.ToListOfParameters();
......
......@@ -165,7 +165,6 @@ internal async Task<ChangeSignatureResult> ChangeSignatureWithContextAsync(Chang
internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureAnalyzedContext context)
{
var notificationService = context.Solution.Workspace.Services.GetService<INotificationService>();
var changeSignatureOptionsService = context.Solution.Workspace.Services.GetService<IChangeSignatureOptionsService>();
// TODO are there any restricitons for extension methods? e.g. remove the first param or reorder it?
......@@ -175,8 +174,7 @@ internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureA
context.Symbol,
context.InsertPosition,
context.ParameterConfiguration,
context.Document,
notificationService);
context.Document);
}
private static async Task<ImmutableArray<ReferencedSymbol>> FindChangeSignatureReferencesAsync(
......
// 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;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.ChangeSignature
{
......@@ -12,8 +10,7 @@ internal interface IChangeSignatureOptionsService : IWorkspaceService
ISymbol symbol,
int insertPosition,
ParameterConfiguration parameters,
Document document,
INotificationService notificationService);
Document document);
AddedParameterResult GetAddedParameter(Document document, int insertPosition);
}
......
......@@ -47,7 +47,7 @@ public AddParameterDialog(IntellisenseTextBoxViewModel intellisenseTextBoxViewMo
DataContext = ViewModel;
// This is for Add. For edit, it should be true by default.
IsValid = false;
_isValid = false;
InitializeComponent();
}
......@@ -57,6 +57,8 @@ private void AddParameterDialog_Loaded(object sender, RoutedEventArgs e)
IntellisenseTextBox typeNameTextBox = new IntellisenseTextBox(
_intellisenseTextBoxView, TypeNameContentControl);
this.TypeNameContentControl.Content = typeNameTextBox;
this.OKButton.IsEnabled = _isValid;
}
private void OK_Click(object sender, RoutedEventArgs e)
......
......@@ -10,8 +10,6 @@
using Microsoft.CodeAnalysis.ChangeSignature;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Microsoft.VisualStudio.Text.Classification;
using Roslyn.Utilities;
......@@ -20,11 +18,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
{
private readonly INotificationService _notificationService;
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly ClassificationTypeMap _classificationTypeMap;
private readonly ParameterConfiguration _originalParameterConfiguration;
private readonly ISymbol _symbol;
private readonly ParameterViewModel _thisParameter;
private readonly List<ParameterViewModel> _parameterGroup1;
......@@ -39,7 +35,6 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
public readonly Document Document;
internal ChangeSignatureDialogViewModel(
INotificationService notificationService,
ParameterConfiguration parameters,
ISymbol symbol,
Document document,
......@@ -48,7 +43,6 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
ClassificationTypeMap classificationTypeMap)
{
_originalParameterConfiguration = parameters;
_notificationService = notificationService;
Document = document;
InsertPosition = insertPosition;
_classificationFormatMap = classificationFormatMap;
......@@ -62,7 +56,6 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
_disabledParameters.Add(_thisParameter);
}
_symbol = symbol;
_declarationParts = symbol.ToDisplayParts(s_symbolDeclarationDisplayFormat);
_parameterGroup1 = parameters.ParametersWithoutDefaultValues.Select(p => new ExistingParameterViewModel(this, p, initialIndex++)).ToList<ParameterViewModel>();
......
......@@ -10,14 +10,9 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using ImportingConstructorAttribute = System.Composition.ImportingConstructorAttribute;
......@@ -30,41 +25,30 @@ internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptio
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly ClassificationTypeMap _classificationTypeMap;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly ITextEditorFactoryService _textEditorFactoryService;
private readonly IContentType _contentType;
private readonly OLE.Interop.IServiceProvider _serviceProvider;
private readonly IProjectionBufferFactoryService _projectionBufferFactoryService;
private readonly IntellisenseTextBoxViewModelFactory _intellisenseTextBoxViewModelFactory;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public VisualStudioChangeSignatureOptionsService(
IClassificationFormatMapService classificationFormatMapService,
ClassificationTypeMap classificationTypeMap,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
ITextEditorFactoryService textEditorFactoryService,
IContentTypeRegistryService contentTypeRegistryService,
IProjectionBufferFactoryService projectionBufferFactoryService,
SVsServiceProvider services)
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory)
{
_classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap("tooltip");
_classificationTypeMap = classificationTypeMap;
_editorAdaptersFactoryService = editorAdaptersFactoryService;
_textEditorFactoryService = textEditorFactoryService;
_contentType = contentTypeRegistryService.GetContentType(ContentTypeNames.CSharpContentType);
_serviceProvider = (OLE.Interop.IServiceProvider)services.GetService(typeof(OLE.Interop.IServiceProvider));
_projectionBufferFactoryService = projectionBufferFactoryService;
_intellisenseTextBoxViewModelFactory = intellisenseTextBoxViewModelFactory;
}
public ChangeSignatureOptionsResult GetChangeSignatureOptions(
ISymbol symbol,
int insertPosition,
ParameterConfiguration parameters,
Document document,
INotificationService notificationService)
Document document)
{
var viewModel = new ChangeSignatureDialogViewModel(
notificationService,
parameters,
symbol,
document,
......@@ -113,92 +97,30 @@ public AddedParameterResult GetAddedParameter(Document document, int insertPosit
var sourceText = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
var documentText = sourceText.ToString();
IVsTextLines vsTextLines = _editorAdaptersFactoryService.CreateVsTextBufferAdapter(_serviceProvider, _contentType) as IVsTextLines;
vsTextLines.InitializeContent(documentText.Insert(insertPosition, ","), documentText.Length);
var viewModels = await _intellisenseTextBoxViewModelFactory.CreateIntellisenseTextBoxViewModelsAsync(
document, _contentType, documentText.Insert(insertPosition, ","),
CreateTrackingSpans, new[] { AddParameterTextViewRole }, cancellationToken).ConfigureAwait(false);
var originalContextBuffer = _editorAdaptersFactoryService.GetDataBuffer(vsTextLines);
// Get the workspace, and from there, the solution and document containing this buffer.
// If there's an ExternalSource, we won't get a document. Give up in that case.
var solution = document.Project.Solution;
return new AddParameterDialog(viewModels[0]);
// Wrap the original ContextBuffer in a projection buffer that we can make read-only
var contextBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
new object[] { originalContextBuffer.CurrentSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive) }, ProjectionBufferOptions.None, _contentType);
// Make projection readonly so we can't edit it by mistake.
using (var regionEdit = contextBuffer.CreateReadOnlyRegionEdit())
ITrackingSpan[] CreateTrackingSpans(IProjectionSnapshot snapshot)
{
regionEdit.CreateReadOnlyRegion(new Span(0, contextBuffer.CurrentSnapshot.Length), SpanTrackingMode.EdgeInclusive, EdgeInsertionMode.Deny);
regionEdit.Apply();
}
// Adjust the context point to ensure that the right information is in scope.
// For example, we may need to move the point to the end of the last statement in a method body
// in order to be able to access all local variables.
// + 1 to support inserted comma
var contextPoint = insertPosition + 1;
// Get the previous span/text. We might have to insert another newline or something.
var previousStatementSpan = contextBuffer.CurrentSnapshot.CreateTrackingSpanFromStartToIndex(contextPoint, SpanTrackingMode.EdgeNegative);
// Get the appropriate ITrackingSpan for the window the user is typing in
var mappedSpan = contextBuffer.CurrentSnapshot.CreateTrackingSpan(contextPoint, 0, SpanTrackingMode.EdgeExclusive);
// Adjust the context point to ensure that the right information is in scope.
// For example, we may need to move the point to the end of the last statement in a method body
// in order to be able to access all local variables.
// + 1 to support inserted comma
var contextPoint = insertPosition + 1;
// Build the tracking span that includes the rest of the file
var restOfFileSpan = contextBuffer.CurrentSnapshot.CreateTrackingSpanFromIndexToEnd(contextPoint, SpanTrackingMode.EdgePositive);
// Get the previous span/text. We might have to insert another newline or something.
var previousStatementSpan = snapshot.CreateTrackingSpanFromStartToIndex(contextPoint, SpanTrackingMode.EdgeNegative);
// Put it all into a projection buffer
var projectionBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
new object[] { previousStatementSpan, mappedSpan, restOfFileSpan }, ProjectionBufferOptions.None, _contentType);
// Get the appropriate ITrackingSpan for the window the user is typing in
var mappedSpan = snapshot.CreateTrackingSpan(contextPoint, 0, SpanTrackingMode.EdgeExclusive);
// Fork the solution using this new primary buffer for the document and all of its linked documents.
var forkedSolution = solution.WithDocumentText(document.Id, projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity);
foreach (var link in document.GetLinkedDocumentIds())
{
forkedSolution = forkedSolution.WithDocumentText(link, projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity);
}
// Put it into a new workspace, and open it and its related documents
// with the projection buffer as the text.
var workspace = new ChangeSignatureWorkspace(forkedSolution, document.Project);
workspace.OpenDocument(workspace.ChangeSignatureDocumentId, originalContextBuffer.AsTextContainer());
foreach (var link in document.GetLinkedDocumentIds())
{
workspace.OpenDocument(link, originalContextBuffer.AsTextContainer());
// Build the tracking span that includes the rest of the file
var restOfFileSpan = snapshot.CreateTrackingSpanFromIndexToEnd(contextPoint, SpanTrackingMode.EdgePositive);
return new ITrackingSpan[] { previousStatementSpan, mappedSpan, restOfFileSpan };
}
// Start getting the compilation so the PartialSolution will be ready when the user starts typing in the window
await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
ITextViewRoleSet roleSet = _textEditorFactoryService.CreateTextViewRoleSet(
PredefinedTextViewRoles.Editable,
PredefinedTextViewRoles.Interactive,
AddParameterTextViewRole);
IVsTextView vsTextView = _editorAdaptersFactoryService.CreateVsTextViewAdapter(_serviceProvider, roleSet);
INITVIEW[] initView = new[] {
new INITVIEW()
{
fSelectionMargin = 0,
fWidgetMargin = 0,
fDragDropMove = 0,
IndentStyle = vsIndentStyle.vsIndentStyleNone
}
};
_editorAdaptersFactoryService.SetDataBuffer(vsTextLines, projectionBuffer);
vsTextView.Initialize(
vsTextLines,
IntPtr.Zero,
(uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
initView);
IWpfTextView wpfTextView = _editorAdaptersFactoryService.GetWpfTextView(vsTextView);
wpfTextView.TextBuffer.ChangeContentType(_contentType, null);
return new AddParameterDialog(new IntellisenseTextBoxViewModel(vsTextView, wpfTextView));
}
}
}
......@@ -17,7 +17,6 @@
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities.Internal;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
......
// 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.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using ImportingConstructorAttribute = System.Composition.ImportingConstructorAttribute;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
[Export(typeof(IntellisenseTextBoxViewModelFactory)), Shared]
internal class IntellisenseTextBoxViewModelFactory
{
private static readonly INITVIEW[] s_InitViews = new[] {
new INITVIEW()
{
fSelectionMargin = 0,
fWidgetMargin = 0,
fDragDropMove = 0,
IndentStyle = vsIndentStyle.vsIndentStyleNone
}
};
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly ITextEditorFactoryService _textEditorFactoryService;
private readonly OLE.Interop.IServiceProvider _serviceProvider;
private readonly IProjectionBufferFactoryService _projectionBufferFactoryService;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public IntellisenseTextBoxViewModelFactory(
IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
ITextEditorFactoryService textEditorFactoryService,
IContentTypeRegistryService contentTypeRegistryService,
IProjectionBufferFactoryService projectionBufferFactoryService,
SVsServiceProvider services)
{
_editorAdaptersFactoryService = editorAdaptersFactoryService;
_textEditorFactoryService = textEditorFactoryService;
_serviceProvider = (OLE.Interop.IServiceProvider)services.GetService(typeof(OLE.Interop.IServiceProvider));
_projectionBufferFactoryService = projectionBufferFactoryService;
}
public async Task<IntellisenseTextBoxViewModel[]> CreateIntellisenseTextBoxViewModelsAsync(
Document document,
IContentType contentType,
string contentString,
Func<IProjectionSnapshot, ITrackingSpan[]> createSpansMethod,
string[] roles, CancellationToken cancellationToken)
{
IVsTextLines vsTextLines = _editorAdaptersFactoryService.CreateVsTextBufferAdapter(_serviceProvider, contentType) as IVsTextLines;
vsTextLines.InitializeContent(contentString, contentString.Length);
var originalContextBuffer = _editorAdaptersFactoryService.GetDataBuffer(vsTextLines);
// Get the workspace, and from there, the solution and document containing this buffer.
// If there's an ExternalSource, we won't get a document. Give up in that case.
var solution = document.Project.Solution;
// Wrap the original ContextBuffer in a projection buffer that we can make read-only
var contextBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
new object[] { originalContextBuffer.CurrentSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive) }, ProjectionBufferOptions.None, contentType);
// Make projection readonly so we can't edit it by mistake.
using (var regionEdit = contextBuffer.CreateReadOnlyRegionEdit())
{
regionEdit.CreateReadOnlyRegion(new Span(0, contextBuffer.CurrentSnapshot.Length), SpanTrackingMode.EdgeInclusive, EdgeInsertionMode.Deny);
regionEdit.Apply();
}
// Put it all into a projection buffer
var projectionBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
createSpansMethod(contextBuffer.CurrentSnapshot),
ProjectionBufferOptions.None, contentType);
// Fork the solution using this new primary buffer for the document and all of its linked documents.
var forkedSolution = solution.WithDocumentText(document.Id, projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity);
foreach (var link in document.GetLinkedDocumentIds())
{
forkedSolution = forkedSolution.WithDocumentText(link, projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity);
}
// Put it into a new workspace, and open it and its related documents
// with the projection buffer as the text.
var workspace = new IntellisenseWorkspace(forkedSolution, document.Project);
workspace.OpenDocument(workspace.ChangeSignatureDocumentId, originalContextBuffer.AsTextContainer());
foreach (var link in document.GetLinkedDocumentIds())
{
workspace.OpenDocument(link, originalContextBuffer.AsTextContainer());
}
// Start getting the compilation so the PartialSolution will be ready when the user starts typing in the window
await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
IntellisenseTextBoxViewModel[] result = new IntellisenseTextBoxViewModel[roles.Length];
for (int i = 0; i < roles.Length; i++)
{
ITextViewRoleSet roleSet = _textEditorFactoryService.CreateTextViewRoleSet(
PredefinedTextViewRoles.Editable,
PredefinedTextViewRoles.Interactive,
roles[i]);
IVsTextView vsTextView = _editorAdaptersFactoryService.CreateVsTextViewAdapter(_serviceProvider, roleSet);
_editorAdaptersFactoryService.SetDataBuffer(vsTextLines, projectionBuffer);
vsTextView.Initialize(
vsTextLines,
IntPtr.Zero,
(uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
s_InitViews);
// Here we need ITextViewModelProvider handling the corresponding role.
IWpfTextView wpfTextView = _editorAdaptersFactoryService.GetWpfTextView(vsTextView);
wpfTextView.TextBuffer.ChangeContentType(contentType, null);
result[i] = new IntellisenseTextBoxViewModel(vsTextView, wpfTextView);
}
return result;
}
}
}
......@@ -5,13 +5,14 @@
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Editor.Options;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
internal class ChangeSignatureWorkspace : Workspace
internal class IntellisenseWorkspace : Workspace
{
public ChangeSignatureWorkspace(Solution solution, Project project)
: base(project.Solution.Workspace.Services.HostServices, nameof(ChangeSignatureWorkspace))
public IntellisenseWorkspace(Solution solution, Project project, string documentText = null)
: base(project.Solution.Workspace.Services.HostServices, nameof(IntellisenseWorkspace))
{
documentText = documentText ?? string.Empty;
// The solution we are handed is still parented by the original workspace. We want to
// inherit it's "no partial solutions" flag so that way this workspace will also act
// deterministically if we're in unit tests
......@@ -19,20 +20,11 @@ public ChangeSignatureWorkspace(Solution solution, Project project)
// Create a new document to hold the temporary code
ChangeSignatureDocumentId = DocumentId.CreateNewId(project.Id);
this.SetCurrentSolution(solution.AddDocument(ChangeSignatureDocumentId, Guid.NewGuid().ToString(), GetDocumentText()));
this.SetCurrentSolution(solution.AddDocument(ChangeSignatureDocumentId, Guid.NewGuid().ToString(), documentText));
Options = Options.WithChangedOption(EditorCompletionOptions.UseSuggestionMode, true);
}
// TODO do we need to keep this?
private static string GetDocumentText()
{
return $@"
{{
}}
";
}
public Document ChangeSignatureDocument => this.CurrentSolution.GetDocument(this.ChangeSignatureDocumentId);
public DocumentId ChangeSignatureDocumentId { get; }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册