提交 e9080362 编写于 作者: A Allison Chou

Merge branch 'AddParameter' of https://github.com/ivanbasov/roslyn into AddParameterIvan

......@@ -315,7 +315,6 @@ public class C3
using (var testState = ChangeSignatureTestState.Create(XElement.Parse(workspaceXml)))
{
testState.TestChangeSignatureOptionsService.IsCancelled = false;
testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature.Select(i => new AddedParameterOrExistingIndex(i)).ToArray();
var result = testState.ChangeSignature();
......
......@@ -249,7 +249,6 @@ void M()
new AddedParameterOrExistingIndex(new AddedParameter("int", "newIntegerParameter", "123")) };
using var testState = ChangeSignatureTestState.Create(XElement.Parse(workspaceXml));
testState.TestChangeSignatureOptionsService.IsCancelled = false;
testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature;
var result = testState.ChangeSignature();
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Windows;
using System.Windows.Documents;
using Microsoft.VisualStudio.Text.Classification;
......
......@@ -25,19 +25,17 @@ protected override ParseOptions GetScriptOptions()
internal async Task TestChangeSignatureViaCodeActionAsync(
string markup,
bool expectedCodeAction = true,
bool isCancelled = false,
int[] updatedSignature = null,
string expectedCode = null,
int index = 0)
=> await TestChangeSignatureViaCodeActionAsync(
markup, updatedSignature?.Select(i => new AddedParameterOrExistingIndex(i)).ToArray(),
expectedCodeAction, isCancelled, expectedCode, index).ConfigureAwait(false);
expectedCodeAction, expectedCode, index).ConfigureAwait(false);
internal async Task TestChangeSignatureViaCodeActionAsync(
string markup,
AddedParameterOrExistingIndex[] updatedSignature,
bool expectedCodeAction = true,
bool isCancelled = false,
string expectedCode = null,
int index = 0)
{
......@@ -47,7 +45,6 @@ protected override ParseOptions GetScriptOptions()
using (var workspace = CreateWorkspaceFromOptions(markup, testOptions))
{
var optionsService = workspace.Services.GetService<IChangeSignatureOptionsService>() as TestChangeSignatureOptionsService;
optionsService.IsCancelled = isCancelled;
optionsService.UpdatedSignature = updatedSignature;
var refactoring = await GetCodeRefactoringAsync(workspace, testOptions);
......@@ -99,7 +96,6 @@ protected override ParseOptions GetScriptOptions()
{
using (var testState = ChangeSignatureTestState.Create(markup, languageName, parseOptions))
{
testState.TestChangeSignatureOptionsService.IsCancelled = false;
testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature;
var result = testState.ChangeSignature();
......
......@@ -14,7 +14,6 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature
[ExportWorkspaceService(typeof(IChangeSignatureOptionsService), ServiceLayer.Default), Shared]
internal class TestChangeSignatureOptionsService : IChangeSignatureOptionsService
{
public bool IsCancelled = true;
public AddedParameterOrExistingIndex[]? UpdatedSignature = null;
[ImportingConstructor]
......@@ -34,21 +33,14 @@ public TestChangeSignatureOptionsService()
ParameterConfiguration parameters)
{
var list = parameters.ToListOfParameters();
List<Parameter?> updateParameters = UpdatedSignature != null
? UpdatedSignature.Select(item => item.IsExisting ? list[item.OldIndex ?? -1] : item.AddedParameter).ToList()
: new List<Parameter?>();
return new ChangeSignatureOptionsResult
{
IsCancelled = IsCancelled,
UpdatedSignature = new SignatureChange(
IEnumerable<Parameter?> updateParameters = UpdatedSignature != null
? UpdatedSignature.Select(item => item.IsExisting ? list[item.OldIndex ?? -1] : item.AddedParameter)
: new Parameter?[0];
return new ChangeSignatureOptionsResult(new SignatureChange(
parameters,
UpdatedSignature == null
? parameters
: ParameterConfiguration.Create(
updateParameters,
parameters.ThisParameter != null,
selectedIndex: 0))
};
: ParameterConfiguration.Create(updateParameters, parameters.ThisParameter != null, selectedIndex: 0)), previewChanges: false);
}
}
}
......@@ -51,7 +51,6 @@ class C
Using testState = ChangeSignatureTestState.Create(workspace)
Dim history = testState.Workspace.GetService(Of ITextUndoHistoryRegistry)().RegisterHistory(testState.Workspace.Documents.First().GetTextBuffer())
testState.TestChangeSignatureOptionsService.IsCancelled = False
testState.TestChangeSignatureOptionsService.UpdatedSignature = permutation
Dim result = testState.ChangeSignature()
......@@ -105,7 +104,6 @@ class C
Using testState = ChangeSignatureTestState.Create(workspace)
Dim history = testState.Workspace.GetService(Of ITextUndoHistoryRegistry)().RegisterHistory(testState.Workspace.Documents.First().GetTextBuffer())
testState.TestChangeSignatureOptionsService.IsCancelled = False
testState.TestChangeSignatureOptionsService.UpdatedSignature = permutation
Dim result = testState.ChangeSignature()
......
......@@ -113,7 +113,14 @@ public CSharpChangeSignatureService()
return default;
}
var insertPosition = TryGetInsertPositionFromDeclaration(matchingNode);
int? insertPositionOpt = TryGetInsertPositionFromDeclaration(matchingNode);
if (insertPositionOpt == null)
{
return default;
}
int insertPosition = insertPositionOpt.Value;
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var symbol = semanticModel.GetDeclaredSymbol(matchingNode, cancellationToken);
if (symbol != null)
......@@ -148,13 +155,13 @@ private static int TryGetSelectedIndexFromDeclaration(int position, SyntaxNode m
// Find the position to insert the new parameter.
// We will insert a new comma and a parameter.
private static int TryGetInsertPositionFromDeclaration(SyntaxNode matchingNode)
private static int? TryGetInsertPositionFromDeclaration(SyntaxNode matchingNode)
{
var parameters = matchingNode.ChildNodes().OfType<ParameterListSyntax>().SingleOrDefault();
if (parameters == null)
{
return 0;
return null;
}
if (parameters.Parameters.Count > 0 &&
......@@ -278,7 +285,7 @@ private SyntaxNode GetNodeContainingTargetNode(SyntaxNode matchingNode)
}
}
public override SyntaxNode ChangeSignature(
public override async Task<SyntaxNode> ChangeSignatureAsync(
Document document,
ISymbol declarationSymbol,
SyntaxNode potentiallyUpdatedNode,
......@@ -289,7 +296,6 @@ private SyntaxNode GetNodeContainingTargetNode(SyntaxNode matchingNode)
var updatedNode = potentiallyUpdatedNode as CSharpSyntaxNode;
// Update <param> tags.
if (updatedNode.IsKind(SyntaxKind.MethodDeclaration) ||
updatedNode.IsKind(SyntaxKind.ConstructorDeclaration) ||
updatedNode.IsKind(SyntaxKind.IndexerDeclaration) ||
......@@ -303,7 +309,6 @@ private SyntaxNode GetNodeContainingTargetNode(SyntaxNode matchingNode)
}
// Update declarations parameter lists
if (updatedNode.IsKind(SyntaxKind.MethodDeclaration))
{
var method = (MethodDeclarationSyntax)updatedNode;
......@@ -392,11 +397,10 @@ private SyntaxNode GetNodeContainingTargetNode(SyntaxNode matchingNode)
}
// Update reference site argument lists
if (updatedNode.IsKind(SyntaxKind.InvocationExpression))
{
var invocation = (InvocationExpressionSyntax)updatedNode;
var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var symbolInfo = semanticModel.GetSymbolInfo((InvocationExpressionSyntax)originalNode, cancellationToken);
var isReducedExtensionMethod = false;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
......@@ -38,7 +40,7 @@ internal abstract class AbstractChangeSignatureService : ILanguageService
public abstract Task<ImmutableArray<SymbolAndProjectId>> DetermineCascadedSymbolsFromDelegateInvoke(
SymbolAndProjectId<IMethodSymbol> symbolAndProjectId, Document document, CancellationToken cancellationToken);
public abstract SyntaxNode ChangeSignature(
public abstract Task<SyntaxNode> ChangeSignatureAsync(
Document document,
ISymbol declarationSymbol,
SyntaxNode potentiallyUpdatedNode,
......@@ -63,25 +65,26 @@ internal ChangeSignatureResult ChangeSignature(Document document, int position,
{
var context = GetContextAsync(document, position, restrictToDeclarations: false, cancellationToken: cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken);
if (context is ChangeSignatureAnalyzedSucceedContext changeSignatureAnalyzedSucceedContext)
{
return ChangeSignatureWithContextAsync(changeSignatureAnalyzedSucceedContext, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken);
}
else
switch (context)
{
var cannotChangeSignatureAnalyzedContext = context as CannotChangeSignatureAnalyzedContext;
switch (cannotChangeSignatureAnalyzedContext.CannotChangeSignatureReason)
{
case CannotChangeSignatureReason.DefinedInMetadata:
errorHandler(FeaturesResources.The_member_is_defined_in_metadata, NotificationSeverity.Error);
break;
case CannotChangeSignatureReason.IncorrectKind:
errorHandler(FeaturesResources.You_can_only_change_the_signature_of_a_constructor_indexer_method_or_delegate, NotificationSeverity.Error);
break;
}
case ChangeSignatureAnalyzedSucceedContext changeSignatureAnalyzedSucceedContext:
return ChangeSignatureWithContextAsync(changeSignatureAnalyzedSucceedContext, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken);
case CannotChangeSignatureAnalyzedContext cannotChangeSignatureAnalyzedContext:
switch (cannotChangeSignatureAnalyzedContext.CannotChangeSignatureReason)
{
case CannotChangeSignatureReason.DefinedInMetadata:
errorHandler(FeaturesResources.The_member_is_defined_in_metadata, NotificationSeverity.Error);
break;
case CannotChangeSignatureReason.IncorrectKind:
errorHandler(FeaturesResources.You_can_only_change_the_signature_of_a_constructor_indexer_method_or_delegate, NotificationSeverity.Error);
break;
}
return new ChangeSignatureResult(succeeded: false);
break;
}
return new ChangeSignatureResult(succeeded: false);
}
internal async Task<ChangeSignatureAnalyzedContext> GetContextAsync(
......@@ -134,7 +137,9 @@ internal ChangeSignatureResult ChangeSignature(Document document, int position,
return new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind);
}
var parameterConfiguration = ParameterConfiguration.Create(symbol.GetParameters().Select(p => new ExistingParameter(p)).ToList<Parameter>(), symbol is IMethodSymbol && (symbol as IMethodSymbol).IsExtensionMethod, selectedIndex);
var parameterConfiguration = ParameterConfiguration.Create(
symbol.GetParameters().Select(p => new ExistingParameter(p)),
symbol.IsExtensionMethod(), selectedIndex);
return new ChangeSignatureAnalyzedSucceedContext(
document, insertPosition, symbol, parameterConfiguration);
......@@ -143,7 +148,7 @@ internal ChangeSignatureResult ChangeSignature(Document document, int position,
private async Task<ChangeSignatureResult> ChangeSignatureWithContextAsync(ChangeSignatureAnalyzedSucceedContext context, CancellationToken cancellationToken)
{
var options = GetChangeSignatureOptions(context);
if (options.IsCancelled)
if (options == null)
{
return new ChangeSignatureResult(succeeded: false);
}
......@@ -157,11 +162,11 @@ internal async Task<ChangeSignatureResult> ChangeSignatureWithContextAsync(Chang
return new ChangeSignatureResult(updatedSolution != null, updatedSolution, context.Symbol.ToDisplayString(), context.Symbol.GetGlyph(), options.PreviewChanges);
}
internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureAnalyzedSucceedContext context)
internal ChangeSignatureOptionsResult? GetChangeSignatureOptions(ChangeSignatureAnalyzedSucceedContext context)
{
var changeSignatureOptionsService = context.Solution.Workspace.Services.GetService<IChangeSignatureOptionsService>();
return changeSignatureOptionsService.GetChangeSignatureOptions(
return changeSignatureOptionsService?.GetChangeSignatureOptions(
context.Document, context.InsertPosition, context.Symbol, context.ParameterConfiguration);
}
......@@ -175,10 +180,9 @@ internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureA
var streamingProgress = new StreamingProgressCollector(
StreamingFindReferencesProgress.Instance);
IImmutableSet<Document> documents = null;
var engine = new FindReferencesSearchEngine(
solution,
documents,
documents: ImmutableSortedSet<Document>.Empty,
ReferenceFinders.DefaultReferenceFinders.Add(DelegateInvokeMethodReferenceFinder.DelegateInvokeMethod),
streamingProgress,
FindReferencesSearchOptions.Default,
......@@ -202,9 +206,9 @@ internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureA
var hasLocationsInMetadata = false;
var symbols = FindChangeSignatureReferencesAsync(
var symbols = await FindChangeSignatureReferencesAsync(
SymbolAndProjectId.Create(declaredSymbol, context.Document.Project.Id),
context.Solution, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken);
context.Solution, cancellationToken).ConfigureAwait(false);
var declaredSymbolParametersCount = declaredSymbol.GetParameters().Length;
......@@ -340,7 +344,13 @@ internal ChangeSignatureOptionsResult GetChangeSignatureOptions(ChangeSignatureA
var newRoot = root.ReplaceNodes(nodes, (originalNode, potentiallyUpdatedNode) =>
{
return updater.ChangeSignature(doc, definitionToUse[originalNode], potentiallyUpdatedNode, originalNode, CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature), cancellationToken);
return updater.ChangeSignatureAsync(
doc,
definitionToUse[originalNode],
potentiallyUpdatedNode,
originalNode,
CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature),
cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken);
});
var annotatedNodes = newRoot.GetAnnotatedNodes<SyntaxNode>(syntaxAnnotation: changeSignatureFormattingAnnotation);
......@@ -445,6 +455,7 @@ private bool TryGetNodeWithEditableSignatureOrAttributes(Location location, Solu
if (!param.IsParams)
{
// If seen a named argument before, add names for subsequent ones.
if ((seenNamedArgument || actualIndex != expectedIndex) && !argument.IsNamed)
{
......
......@@ -28,7 +28,7 @@ public override object GetOptions(CancellationToken cancellationToken)
protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(object options, CancellationToken cancellationToken)
{
if (options is ChangeSignatureOptionsResult changeSignatureOptions && !changeSignatureOptions.IsCancelled)
if (options is ChangeSignatureOptionsResult changeSignatureOptions && changeSignatureOptions != null)
{
var changeSignatureResult = await _changeSignatureService.ChangeSignatureWithContextAsync(_context, changeSignatureOptions, cancellationToken).ConfigureAwait(false);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
namespace Microsoft.CodeAnalysis.ChangeSignature
{
internal sealed class ChangeSignatureOptionsResult
{
public bool IsCancelled { get; set; }
public bool PreviewChanges { get; internal set; }
public SignatureChange UpdatedSignature { get; set; }
public readonly bool PreviewChanges;
public readonly SignatureChange UpdatedSignature;
public ChangeSignatureOptionsResult(SignatureChange updatedSignature, bool previewChanges)
{
UpdatedSignature = updatedSignature;
PreviewChanges = previewChanges;
}
}
}
......@@ -16,7 +16,7 @@ internal interface IChangeSignatureOptionsService : IWorkspaceService
/// <param name="symbol">the symbol for changing the signature</param>
/// <param name="parameters">existing parameters of the symbol</param>
/// <returns></returns>
ChangeSignatureOptionsResult GetChangeSignatureOptions(
ChangeSignatureOptionsResult? GetChangeSignatureOptions(
Document document,
int insertPosition,
ISymbol symbol,
......
......@@ -10,17 +10,17 @@ namespace Microsoft.CodeAnalysis.ChangeSignature
{
internal sealed class ParameterConfiguration
{
public readonly Parameter? ThisParameter;
public readonly ExistingParameter? ThisParameter;
public readonly ImmutableArray<Parameter> ParametersWithoutDefaultValues;
public readonly ImmutableArray<Parameter> RemainingEditableParameters;
public readonly Parameter? ParamsParameter;
public readonly ExistingParameter? ParamsParameter;
public readonly int SelectedIndex;
public ParameterConfiguration(
Parameter? thisParameter,
ExistingParameter? thisParameter,
ImmutableArray<Parameter> parametersWithoutDefaultValues,
ImmutableArray<Parameter> remainingEditableParameters,
Parameter? paramsParameter,
ExistingParameter? paramsParameter,
int selectedIndex)
{
ThisParameter = thisParameter;
......@@ -30,23 +30,24 @@ internal sealed class ParameterConfiguration
SelectedIndex = selectedIndex;
}
public static ParameterConfiguration Create(List<Parameter?> parameters, bool isExtensionMethod, int selectedIndex)
public static ParameterConfiguration Create(IEnumerable<Parameter?> parameters, bool isExtensionMethod, int selectedIndex)
{
Parameter? thisParameter = null;
var parametersList = parameters.ToList();
ExistingParameter? thisParameter = null;
var parametersWithoutDefaultValues = ImmutableArray.CreateBuilder<Parameter>();
var remainingReorderableParameters = ImmutableArray.CreateBuilder<Parameter>();
Parameter? paramsParameter = null;
ExistingParameter? paramsParameter = null;
if (parameters.Count > 0 && isExtensionMethod)
if (parametersList.Count > 0 && isExtensionMethod)
{
thisParameter = parameters[0];
parameters.RemoveAt(0);
thisParameter = parametersList[0] as ExistingParameter;
parametersList.RemoveAt(0);
}
if (parameters.Count > 0 && (parameters[parameters.Count - 1] as ExistingParameter)?.Symbol.IsParams == true)
if (parametersList.Count > 0 && (parametersList[parametersList.Count - 1] as ExistingParameter)?.Symbol.IsParams == true)
{
paramsParameter = parameters[parameters.Count - 1];
parameters.RemoveAt(parameters.Count - 1);
paramsParameter = parametersList[parametersList.Count - 1] as ExistingParameter;
parametersList.RemoveAt(parametersList.Count - 1);
}
var seenDefaultValues = false;
......@@ -67,7 +68,7 @@ public static ParameterConfiguration Create(List<Parameter?> parameters, bool is
}
internal ParameterConfiguration WithoutAddedParameters()
=> Create(ToListOfParameters().OfType<ExistingParameter>().ToList<Parameter?>(), ThisParameter != null, selectedIndex: 0);
=> Create(ToListOfParameters().OfType<ExistingParameter>(), ThisParameter != null, selectedIndex: 0);
public List<Parameter> ToListOfParameters()
{
......
......@@ -270,7 +270,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature
Return matchingNode
End Function
Public Overrides Function ChangeSignature(document As Document, declarationSymbol As ISymbol, potentiallyUpdatedNode As SyntaxNode, originalNode As SyntaxNode, updatedSignature As SignatureChange, cancellationToken As CancellationToken) As SyntaxNode
Public Overrides Async Function ChangeSignatureAsync(document As Document, declarationSymbol As ISymbol, potentiallyUpdatedNode As SyntaxNode, originalNode As SyntaxNode, updatedSignature As SignatureChange, cancellationToken As CancellationToken) As Task(Of SyntaxNode)
Dim vbnode = DirectCast(potentiallyUpdatedNode, VisualBasicSyntaxNode)
If vbnode.IsKind(SyntaxKind.SubStatement) OrElse
vbnode.IsKind(SyntaxKind.FunctionStatement) OrElse
......@@ -333,7 +333,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature
If vbnode.IsKind(SyntaxKind.InvocationExpression) Then
Dim invocation = DirectCast(vbnode, InvocationExpressionSyntax)
Dim semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken)
Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
Dim isReducedExtensionMethod = False
Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, InvocationExpressionSyntax))
......
// 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.Collections.Generic;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature;
using Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Utilities;
using static Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel;
namespace Microsoft.VisualStudio.LanguageServices.CSharp.ChangeSignature
{
[ExportLanguageService(typeof(IChangeSignatureLanguageService), LanguageNames.CSharp), Shared]
internal class CSharpChangeSignatureLanguageService : ChangeSignatureLanguageService
{
public override IntellisenseTextBoxViewModel[] CreateViewModels(
string[] rolesCollectionType,
string[] rolesCollectionName,
int insertPosition,
Document document,
string documentText,
IContentType contentType,
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory)
{
var rolesCollections = new[] { rolesCollectionType, rolesCollectionName };
return intellisenseTextBoxViewModelFactory.CreateIntellisenseTextBoxViewModels(
document, contentType, documentText.Insert(insertPosition, ", "),
CreateTrackingSpans, rolesCollections);
ITrackingSpan[] CreateTrackingSpans(ITextSnapshot snapshot)
{
// 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
return CreateTrackingSpansHelper(snapshot, contextPoint: insertPosition + 1, spaceBetweenTypeAndName: 1);
}
}
public override void GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel, List<SymbolDisplayPart> displayParts)
{
displayParts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.Keyword, null, addedParameterViewModel.Type));
displayParts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.Space, null, " "));
displayParts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.ParameterName, null, addedParameterViewModel.Parameter)); ;
}
public override bool IsTypeNameValid(string typeName) => !SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics;
}
}
// 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.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature;
using Microsoft.VisualStudio.Text;
using static Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel;
namespace Microsoft.VisualStudio.LanguageServices.CSharp.ChangeSignature
{
[ExportLanguageService(typeof(IChangeSignatureViewModelFactoryService), LanguageNames.CSharp), Shared]
internal class CSharpChangeSignatureViewModelFactoryService : ChangeSignatureViewModelFactoryService
{
// 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
protected override ITrackingSpan[] CreateSpansMethod(ITextSnapshot textSnapshot, int insertPosition)
=> CreateTrackingSpansHelper(textSnapshot, contextPoint: insertPosition + 1, spaceBetweenTypeAndName: 1);
protected override string TextToInsert => ", ";
protected override string ContentTypeName => ContentTypeNames.CSharpContentType;
public override SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel)
=> new[] {
new SymbolDisplayPart(SymbolDisplayPartKind.Keyword, null, addedParameterViewModel.Type),
new SymbolDisplayPart(SymbolDisplayPartKind.Space, null, " "),
new SymbolDisplayPart(SymbolDisplayPartKind.ParameterName, null, addedParameterViewModel.ParameterName)};
public override bool IsTypeNameValid(string typeName) => !SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics;
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Microsoft.VisualStudio.PlatformUI;
......@@ -7,6 +10,7 @@
using Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
......@@ -16,8 +20,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
internal partial class AddParameterDialog : DialogWindow
{
public readonly AddParameterDialogViewModel ViewModel;
private readonly IntellisenseTextBoxViewModel _typeIntellisenseTextBoxViewModel;
private readonly IntellisenseTextBoxViewModel _nameIntellisenseTextBoxViewModel;
private readonly Task<ChangeSignatureIntellisenseTextBoxesViewModel?> _createIntellisenseTextBoxViewModelsTask;
private readonly IntellisenseTextBoxFactory _intellisenseTextBoxFactory;
private readonly Document _document;
public string OK { get { return ServicesVSResources.OK; } }
......@@ -32,16 +36,17 @@ internal partial class AddParameterDialog : DialogWindow
public string AddParameterDialogTitle { get { return ServicesVSResources.Add_Parameter; } }
public AddParameterDialog(
IntellisenseTextBoxViewModel typeIntellisenseTextBoxViewModel,
IntellisenseTextBoxViewModel nameIntellisenseTextBoxViewModel,
INotificationService notificationService,
Task<ChangeSignatureIntellisenseTextBoxesViewModel?> createViewModelsTask,
IntellisenseTextBoxFactory intellisenseTextBoxFactory,
INotificationService? notificationService,
Document document)
{
// The current implementation supports Add only.
// The dialog should be initialized the other way if called for Edit.
ViewModel = new AddParameterDialogViewModel(notificationService);
_typeIntellisenseTextBoxViewModel = typeIntellisenseTextBoxViewModel;
_nameIntellisenseTextBoxViewModel = nameIntellisenseTextBoxViewModel;
_createIntellisenseTextBoxViewModelsTask = createViewModelsTask;
_intellisenseTextBoxFactory = intellisenseTextBoxFactory;
_document = document;
this.Loaded += AddParameterDialog_Loaded;
DataContext = ViewModel;
......@@ -51,13 +56,17 @@ internal partial class AddParameterDialog : DialogWindow
private void AddParameterDialog_Loaded(object sender, RoutedEventArgs e)
{
IntellisenseTextBox typeTextBox = new IntellisenseTextBox(
_typeIntellisenseTextBoxViewModel, TypeContentControl);
this.TypeContentControl.Content = typeTextBox;
var viewModels = _createIntellisenseTextBoxViewModelsTask.Result;
IntellisenseTextBox nameTextBox = new IntellisenseTextBox(
_nameIntellisenseTextBoxViewModel, NameContentControl);
this.NameContentControl.Content = nameTextBox;
if (viewModels != null)
{
var languageService = _document.GetRequiredLanguageService<IChangeSignatureViewModelFactoryService>();
this.TypeContentControl.Content = _intellisenseTextBoxFactory.Create(
viewModels.Value.TypeIntellisenseTextBoxViewModel, TypeContentControl);
this.NameContentControl.Content = _intellisenseTextBoxFactory.Create(
viewModels.Value.NameIntellisenseTextBoxViewModel, NameContentControl);
}
}
private void OK_Click(object sender, RoutedEventArgs e)
......@@ -79,7 +88,7 @@ private void Cancel_Click(object sender, RoutedEventArgs e)
private void TypeOrNameContentControl_PreviewKeyDown(object sender, KeyEventArgs e)
{
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
UIElement? elementWithFocus = Keyboard.FocusedElement as UIElement;
if (elementWithFocus is IWpfTextView)
{
......
......@@ -12,9 +12,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal class AddParameterDialogViewModel : AbstractNotifyPropertyChanged
{
private readonly INotificationService _notificationService;
private readonly INotificationService? _notificationService;
public AddParameterDialogViewModel(INotificationService notificationService)
public AddParameterDialogViewModel(INotificationService? notificationService)
{
_notificationService = notificationService;
ParameterName = string.Empty;
......@@ -53,12 +53,12 @@ internal bool TrySubmit(Document document)
private void SendFailureNotification(string message)
{
_notificationService.SendNotification(message, severity: NotificationSeverity.Information);
_notificationService?.SendNotification(message, severity: NotificationSeverity.Information);
}
private bool IsParameterTypeValid(string typeName, Document document)
{
var languageService = document.GetRequiredLanguageService<IChangeSignatureLanguageService>();
var languageService = document.GetRequiredLanguageService<IChangeSignatureViewModelFactoryService>();
return languageService.IsTypeNameValid(typeName);
}
......
......@@ -12,7 +12,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
[Export(typeof(ITextViewModelProvider))]
[ContentType(ContentTypeNames.RoslynContentType)]
[TextViewRole(VisualStudioChangeSignatureOptionsService.AddParameterTextViewRole)]
[TextViewRole(ChangeSignatureViewModelFactoryService.AddParameterTextViewRole)]
internal class AddParameterTextViewModelProvider : ITextViewModelProvider
{
public IProjectionBufferFactoryService ProjectionBufferFactoryService { get; }
......@@ -34,7 +34,7 @@ public ITextViewModel CreateTextViewModel(ITextDataModel dataModel, ITextViewRol
// 4. The rest of the document.
// Please note that for VB we should use another structure: start, name, " AS ", type, rest
int index;
if (roles.Contains(VisualStudioChangeSignatureOptionsService.AddParameterTypeTextViewRole))
if (roles.Contains(ChangeSignatureViewModelFactoryService.AddParameterTypeTextViewRole))
{
index = 1;
}
......
......@@ -136,6 +136,11 @@ private void Add_Click(object sender, RoutedEventArgs e)
if (result != null)
{
if (!string.IsNullOrWhiteSpace(result.CallSiteValue))
{
result = new AddedParameter(result.TypeName, result.ParameterName, ServicesVSResources.ChangeSignature_NewParameterIntroduceTODOVariable);
}
_viewModel.AddParameter(result);
}
......
......@@ -25,10 +25,13 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
private readonly INotificationService _notificationService;
private readonly ParameterConfiguration _originalParameterConfiguration;
private readonly ParameterViewModel _thisParameter;
// This can be changed to ParameterViewModel if we will allow adding 'this' parameter.
private readonly ExistingParameterViewModel _thisParameter;
private readonly List<ParameterViewModel> _parametersWithoutDefaultValues;
private readonly List<ParameterViewModel> _parametersWithDefaultValues;
private readonly ParameterViewModel _paramsParameter;
// This can be changed to ParameterViewModel if we will allow adding 'params' parameter.
private readonly ExistingParameterViewModel _paramsParameter;
private HashSet<ParameterViewModel> _disabledParameters = new HashSet<ParameterViewModel>();
public readonly int InsertPosition;
......@@ -66,8 +69,8 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
_declarationParts = symbol.ToDisplayParts(s_symbolDeclarationDisplayFormat);
_parametersWithoutDefaultValues = parameters.ParametersWithoutDefaultValues.Select(p => new ExistingParameterViewModel(this, p, initialIndex++)).ToList<ParameterViewModel>();
_parametersWithDefaultValues = parameters.RemainingEditableParameters.Select(p => new ExistingParameterViewModel(this, p, initialIndex++)).ToList<ParameterViewModel>();
_parametersWithoutDefaultValues = CreateParameterViewModels(parameters.ParametersWithoutDefaultValues, ref initialIndex);
_parametersWithDefaultValues = CreateParameterViewModels(parameters.RemainingEditableParameters, ref initialIndex);
if (parameters.ParamsParameter != null)
{
......@@ -92,6 +95,18 @@ internal class ChangeSignatureDialogViewModel : AbstractNotifyPropertyChanged
}
}
List<ParameterViewModel> CreateParameterViewModels(ImmutableArray<Parameter> parameters, ref int initialIndex)
{
var list = new List<ParameterViewModel>();
foreach (ExistingParameter existingParameter in parameters)
{
list.Add(new ExistingParameterViewModel(this, existingParameter, initialIndex));
initialIndex++;
}
return list;
}
public int GetStartingSelectionIndex()
{
if (_thisParameter == null)
......@@ -240,9 +255,9 @@ internal ParameterConfiguration GetParameterConfiguration()
{
return new ParameterConfiguration(
_originalParameterConfiguration.ThisParameter,
_parametersWithoutDefaultValues.Where(p => !p.IsRemoved).Select(p => p.CreateParameter()).ToImmutableArray(),
_parametersWithDefaultValues.Where(p => !p.IsRemoved).Select(p => p.CreateParameter()).ToImmutableArray(),
(_paramsParameter == null || _paramsParameter.IsRemoved) ? null : (_paramsParameter as ExistingParameterViewModel).CreateParameter(),
_parametersWithoutDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter).ToImmutableArray(),
_parametersWithDefaultValues.Where(p => !p.IsRemoved).Select(p => p.Parameter).ToImmutableArray(),
(_paramsParameter == null || _paramsParameter.IsRemoved) ? null : _paramsParameter.Parameter as ExistingParameter,
selectedIndex: -1);
}
......@@ -330,8 +345,8 @@ private List<SymbolDisplayPart> GetSignatureDisplayParts()
break;
case AddedParameterViewModel addedParameterViewModel:
var languageService = Document.GetLanguageService<IChangeSignatureLanguageService>();
languageService.GeneratePreviewDisplayParts(addedParameterViewModel, displayParts);
var languageService = Document.GetLanguageService<IChangeSignatureViewModelFactoryService>();
displayParts.AddRange(languageService.GeneratePreviewDisplayParts(addedParameterViewModel));
break;
default:
......@@ -440,8 +455,8 @@ internal bool TrySubmit()
{
var canSubmit = AllParameters.Any(p => p.IsRemoved) ||
AllParameters.Any(p => p is AddedParameterViewModel) ||
!_parametersWithoutDefaultValues.Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.ParametersWithoutDefaultValues.Cast<ExistingParameter>().Select(p => p.Symbol)) ||
!_parametersWithDefaultValues.Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.RemainingEditableParameters.Cast<ExistingParameter>().Select(p => p.Symbol));
!_parametersWithoutDefaultValues.OfType<ExistingParameterViewModel>().Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.ParametersWithoutDefaultValues.Cast<ExistingParameter>().Select(p => p.Symbol)) ||
!_parametersWithDefaultValues.OfType<ExistingParameterViewModel>().Select(p => p.ParameterSymbol).SequenceEqual(_originalParameterConfiguration.RemainingEditableParameters.Cast<ExistingParameter>().Select(p => p.Symbol));
if (!canSubmit)
{
......@@ -543,30 +558,43 @@ public abstract class ParameterViewModel
{
protected readonly ChangeSignatureDialogViewModel changeSignatureDialogViewModel;
public abstract Parameter Parameter { get; }
public abstract string Type { get; }
public abstract string Parameter { get; }
public abstract string ParameterName { get; }
public abstract bool IsRemoved { get; set; }
public abstract string ShortAutomationText { get; }
public abstract string FullAutomationText { get; }
public abstract bool IsDisabled { get; }
public abstract string Callsite { get; }
public abstract string CallSite { get; }
public ParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel)
{
this.changeSignatureDialogViewModel = changeSignatureDialogViewModel;
}
internal abstract Parameter CreateParameter();
public abstract string InitialIndex { get; }
public abstract string Modifier { get; }
public abstract string Default { get; }
public abstract IParameterSymbol ParameterSymbol { get; }
public virtual string FullAutomationText
{
get
{
var text = $"{Modifier} {Type} {Parameter}";
if (!string.IsNullOrWhiteSpace(Default))
{
text += $" = {Default}";
}
return text;
}
}
}
public class AddedParameterViewModel : ParameterViewModel
{
private readonly AddedParameter _addedParameter;
public override Parameter Parameter => _addedParameter;
public readonly AddedParameter _addedParameter;
public AddedParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel, AddedParameter addedParameter)
: base(changeSignatureDialogViewModel)
......@@ -576,46 +604,23 @@ public AddedParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDia
public override string Type => _addedParameter.TypeName;
public override string Parameter => _addedParameter.ParameterName;
public override string ParameterName => _addedParameter.ParameterName;
public override bool IsRemoved { get => false; set => throw new InvalidOperationException(); }
public override string ShortAutomationText => $"{Type} {Parameter}";
public override string ShortAutomationText => $"{Type} {ParameterName}";
public override string FullAutomationText
{
get
{
var text = ServicesVSResources.Added_Parameter;
text += $"{Modifier} {Type} {Parameter}";
if (!string.IsNullOrWhiteSpace(Default))
{
text += $" = {Default}";
}
text += string.Format(ServicesVSResources.Inserting_call_site_value_0, Callsite);
return text;
var baseText = base.FullAutomationText;
return ServicesVSResources.Added_Parameter + baseText + string.Format(ServicesVSResources.Inserting_call_site_value_0, CallSite);
}
}
public override bool IsDisabled => false;
public override string Callsite
{
get
{
if (!string.IsNullOrWhiteSpace(_addedParameter.CallSiteValue))
{
return _addedParameter.CallSiteValue;
}
return ServicesVSResources.ChangeSignature_NewParameterIntroduceTODOVariable;
}
}
internal override Parameter CreateParameter()
=> new AddedParameter(Type, Parameter, Callsite);
public override string CallSite => _addedParameter.CallSiteValue;
public override string InitialIndex => ServicesVSResources.ChangeSignature_NewParameterIndicator;
......@@ -624,46 +629,32 @@ internal override Parameter CreateParameter()
// Only required parameters are supported currently
public override string Default => string.Empty;
// Use null as a marker that this is an added parameter
public override IParameterSymbol ParameterSymbol => null;
}
#nullable enable
public class ExistingParameterViewModel : ParameterViewModel
{
public override IParameterSymbol ParameterSymbol { get; }
public IParameterSymbol ParameterSymbol => _existingParameter.Symbol;
private readonly ExistingParameter _existingParameter;
public ExistingParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel, Parameter parameter, int initialIndex)
public override Parameter Parameter => _existingParameter;
public ExistingParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogViewModel, ExistingParameter existingParameter, int initialIndex)
: base(changeSignatureDialogViewModel)
{
ParameterSymbol = (parameter as ExistingParameter).Symbol;
_existingParameter = existingParameter;
InitialIndex = initialIndex.ToString();
}
internal override Parameter CreateParameter()
{
return new ExistingParameter(ParameterSymbol);
}
public override string ShortAutomationText => $"{Type} {Parameter}";
public override string FullAutomationText
{
get
{
var text = $"{Modifier} {Type} {Parameter}";
if (!string.IsNullOrWhiteSpace(Default))
{
text += $" = {Default}";
}
return text;
}
}
public override string Callsite => string.Empty;
public override string CallSite => string.Empty;
public override string InitialIndex { get; }
#nullable disable
public override string Modifier
{
get
......@@ -705,9 +696,11 @@ string ModifierText(string @out = default, string @ref = default, string @in = d
}
}
#nullable enable
public override string Type => ParameterSymbol.Type.ToDisplayString(s_parameterDisplayFormat);
public override string Parameter => ParameterSymbol.Name;
public override string ParameterName => ParameterSymbol.Name;
public override string Default
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal struct ChangeSignatureIntellisenseTextBoxesViewModel
{
public readonly IntellisenseTextBoxViewModel TypeIntellisenseTextBoxViewModel;
public readonly IntellisenseTextBoxViewModel NameIntellisenseTextBoxViewModel;
public ChangeSignatureIntellisenseTextBoxesViewModel(IntellisenseTextBoxViewModel typeIntellisenseTextBoxViewModel, IntellisenseTextBoxViewModel nameIntellisenseTextBoxViewModel)
{
this.TypeIntellisenseTextBoxViewModel = typeIntellisenseTextBoxViewModel;
this.NameIntellisenseTextBoxViewModel = nameIntellisenseTextBoxViewModel;
}
}
}
......@@ -2,34 +2,61 @@
#nullable enable
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal abstract class ChangeSignatureLanguageService : IChangeSignatureLanguageService
internal abstract class ChangeSignatureViewModelFactoryService : IChangeSignatureViewModelFactoryService
{
public abstract IntellisenseTextBoxViewModel[] CreateViewModels(
string[] rolesCollectionType,
string[] rolesCollectionName,
int insertPosition,
public const string AddParameterTextViewRole = "AddParameter";
public const string AddParameterTypeTextViewRole = "AddParameterType";
public const string AddParameterNameTextViewRole = "AddParameterName";
private static string[] rolesCollectionForTypeTextBox = new[] { PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive,
AddParameterTextViewRole, AddParameterTypeTextViewRole };
private static string[] rolesCollectionForNameTextBox = new[] { PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive,
AddParameterTextViewRole, AddParameterNameTextViewRole };
private static string[][] rolesCollecitons = new[] { rolesCollectionForTypeTextBox, rolesCollectionForNameTextBox };
public async Task<ChangeSignatureIntellisenseTextBoxesViewModel?> CreateViewModelsAsync(
IContentTypeRegistryService contentTypeRegistryService,
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory,
Document document,
string documentText,
IContentType contentType,
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory);
int insertPosition)
{
var viewModels = await intellisenseTextBoxViewModelFactory.CreateIntellisenseTextBoxViewModelsAsync(
document, contentTypeRegistryService.GetContentType(ContentTypeName), insertPosition, TextToInsert, CreateSpansMethod, rolesCollecitons).ConfigureAwait(false);
public abstract void GeneratePreviewDisplayParts(
ChangeSignatureDialogViewModel.AddedParameterViewModel addedParameterViewModel, List<SymbolDisplayPart> displayParts);
if (viewModels == null)
{
return null;
}
return new ChangeSignatureIntellisenseTextBoxesViewModel(viewModels[0], viewModels[1]);
}
public abstract SymbolDisplayPart[] GeneratePreviewDisplayParts(
ChangeSignatureDialogViewModel.AddedParameterViewModel addedParameterViewModel);
public abstract bool IsTypeNameValid(string typeName);
protected abstract ITrackingSpan[] CreateSpansMethod(ITextSnapshot textSnapshot, int insertPosition);
protected abstract string TextToInsert { get; }
protected abstract string ContentTypeName { get; }
protected ITrackingSpan[] CreateTrackingSpansHelper(ITextSnapshot snapshot, int contextPoint, int spaceBetweenTypeAndName)
{
// Get the previous span/text.
var previousStatementSpan = snapshot.CreateTrackingSpanFromStartToIndex(contextPoint, SpanTrackingMode.EdgeNegative);
var previousStatementSpan = snapshot.CreateTrackingSpan(Span.FromBounds(0, contextPoint), SpanTrackingMode.EdgeNegative);
// Get the appropriate ITrackingSpan for the window the user is typing in.
// mappedSpan1 is the 'Type' field for C# and 'Name' for VB.
......@@ -42,7 +69,7 @@ protected ITrackingSpan[] CreateTrackingSpansHelper(ITextSnapshot snapshot, int
var mappedSpan2 = snapshot.CreateTrackingSpan(contextPoint + spaceBetweenTypeAndName, 0, SpanTrackingMode.EdgeExclusive);
// Build the tracking span that includes the rest of the file.
var restOfFileSpan = snapshot.CreateTrackingSpanFromIndexToEnd(contextPoint + spaceBetweenTypeAndName, SpanTrackingMode.EdgePositive);
var restOfFileSpan = snapshot.CreateTrackingSpan(Span.FromBounds(contextPoint + spaceBetweenTypeAndName, snapshot.Length), SpanTrackingMode.EdgePositive);
// This array as a whole should encompass the span of the entire file.
return new ITrackingSpan[] { previousStatementSpan, mappedSpan1, spaceSpan, mappedSpan2, restOfFileSpan };
......
......@@ -2,7 +2,7 @@
#nullable enable
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls;
......@@ -11,18 +11,15 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal interface IChangeSignatureLanguageService : ILanguageService
internal interface IChangeSignatureViewModelFactoryService : ILanguageService
{
IntellisenseTextBoxViewModel[] CreateViewModels(
string[] rolesCollectionType,
string[] rolesCollectionName,
int insertPosition,
Task<ChangeSignatureIntellisenseTextBoxesViewModel?> CreateViewModelsAsync(
IContentTypeRegistryService contentTypeRegistryService,
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory,
Document document,
string documentText,
IContentType contentType,
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory);
int insertPosition);
void GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel, List<SymbolDisplayPart> displayParts);
SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel);
bool IsTypeNameValid(string typeName);
}
......
......@@ -4,18 +4,14 @@
using System;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.ChangeSignature;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
......@@ -23,14 +19,11 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
[ExportWorkspaceService(typeof(IChangeSignatureOptionsService), ServiceLayer.Host), Shared]
internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptionsService
{
public const string AddParameterTextViewRole = "AddParameter";
public const string AddParameterTypeTextViewRole = "AddParameterType";
public const string AddParameterNameTextViewRole = "AddParameterName";
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly ClassificationTypeMap _classificationTypeMap;
private readonly IContentType _contentType;
private readonly IContentTypeRegistryService _contentTypeRegistryService;
private readonly IntellisenseTextBoxViewModelFactory _intellisenseTextBoxViewModelFactory;
private readonly IntellisenseTextBoxFactory _intellisenseTextBoxFactory;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
......@@ -38,15 +31,17 @@ internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptio
IClassificationFormatMapService classificationFormatMapService,
ClassificationTypeMap classificationTypeMap,
IContentTypeRegistryService contentTypeRegistryService,
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory)
IntellisenseTextBoxViewModelFactory intellisenseTextBoxViewModelFactory,
IntellisenseTextBoxFactory intellisenseTextBoxFactory)
{
_classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap("tooltip");
_classificationTypeMap = classificationTypeMap;
_contentType = contentTypeRegistryService.GetContentType(ContentTypeNames.CSharpContentType);
_contentTypeRegistryService = contentTypeRegistryService;
_intellisenseTextBoxViewModelFactory = intellisenseTextBoxViewModelFactory;
_intellisenseTextBoxFactory = intellisenseTextBoxFactory;
}
public ChangeSignatureOptionsResult GetChangeSignatureOptions(
public ChangeSignatureOptionsResult? GetChangeSignatureOptions(
Document document,
int insertPosition,
ISymbol symbol,
......@@ -65,61 +60,31 @@ internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptio
if (result.HasValue && result.Value)
{
return new ChangeSignatureOptionsResult { IsCancelled = false, UpdatedSignature = new SignatureChange(parameters, viewModel.GetParameterConfiguration()), PreviewChanges = viewModel.PreviewChanges };
return new ChangeSignatureOptionsResult(new SignatureChange(parameters, viewModel.GetParameterConfiguration()), previewChanges: viewModel.PreviewChanges);
}
return new ChangeSignatureOptionsResult { IsCancelled = true };
return null;
}
public AddedParameter? GetAddedParameter(Document document, int insertPosition)
{
var dialog = CreateAddParameterDialog(document, insertPosition);
if (dialog != null)
{
var result = dialog.ShowModal();
if (result.HasValue && result.Value)
{
var viewModel = dialog.ViewModel;
return new AddedParameter(
viewModel.TypeName,
viewModel.ParameterName,
viewModel.CallSiteValue);
}
}
var languageService = document.GetRequiredLanguageService<IChangeSignatureViewModelFactoryService>();
var viewModelsCreationTask = languageService.CreateViewModelsAsync(
_contentTypeRegistryService, _intellisenseTextBoxViewModelFactory, document, insertPosition);
return null;
}
var dialog = new AddParameterDialog(viewModelsCreationTask, _intellisenseTextBoxFactory, document.Project.Solution.Workspace.Services.GetService<INotificationService>(), document);
var result = dialog.ShowModal();
private AddParameterDialog? CreateAddParameterDialog(Document document, int insertPosition)
{
// TODO to be addressed in this PR
// Should not create documentText here. Should move it later.
var syntaxTree = document.GetSyntaxTreeAsync(CancellationToken.None).Result;
if (syntaxTree == null)
if (result.HasValue && result.Value)
{
return null;
var viewModel = dialog.ViewModel;
return new AddedParameter(
viewModel.TypeName,
viewModel.ParameterName,
viewModel.CallSiteValue);
}
var sourceText = syntaxTree.GetTextAsync(CancellationToken.None).Result;
var documentText = sourceText.ToString();
var rolesCollectionForTypeTextBox = new[] { PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive,
AddParameterTextViewRole, AddParameterTypeTextViewRole };
var rolesCollectionForNameTextBox = new[] { PredefinedTextViewRoles.Editable, PredefinedTextViewRoles.Interactive,
AddParameterTextViewRole, AddParameterNameTextViewRole };
var languageService = document.GetRequiredLanguageService<IChangeSignatureLanguageService>();
var viewModels = languageService.CreateViewModels(
rolesCollectionForTypeTextBox,
rolesCollectionForNameTextBox,
insertPosition,
document,
documentText,
_contentType,
_intellisenseTextBoxViewModelFactory);
return new AddParameterDialog(viewModels[0], viewModels[1], document.Project.Solution.Workspace.Services.GetService<INotificationService>(), document);
return null;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.ComponentModel.Design;
using System.Composition;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Automation;
......@@ -9,7 +12,6 @@
using System.Windows.Data;
using System.Windows.Interop;
using System.Windows.Media;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.OLE.Interop;
......@@ -36,7 +38,7 @@ internal class IntellisenseTextBox : FrameworkElement, IOleCommandTarget
/// <summary>
/// The reference to the next command handler in the view filter chain
/// </summary>
private IOleCommandTarget _nextCommandTarget = null;
private IOleCommandTarget? _nextCommandTarget = null;
/// <summary>
/// Used for instructing the editor control to carry out certain operations
......@@ -46,13 +48,52 @@ internal class IntellisenseTextBox : FrameworkElement, IOleCommandTarget
/// <summary>
/// Appearance category of text view in the intellisense textbox
/// </summary>
private const string AppearanceCategory = "IntellisenseTextBlock";
public const string AppearanceCategory = "IntellisenseTextBlock";
public readonly string ContainerName;
public IntellisenseTextBox(IntellisenseTextBoxViewModel viewModel, ContentControl container)
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly IVsEditorAdaptersFactoryService _editorAdapterFactory;
public IntellisenseTextBox(
IEditorOperationsFactoryService editorOperationsFactoryService,
IClassificationFormatMap classificationFormatMap,
IVsEditorAdaptersFactoryService editorAdapterFactory,
IntellisenseTextBoxViewModel viewModel,
ContentControl container) : base()
{
this.InitializeEditorControl(viewModel, container);
_classificationFormatMap = classificationFormatMap;
_editorAdapterFactory = editorAdapterFactory;
this._editorOperations = editorOperationsFactoryService.GetEditorOperations(viewModel.WpfTextView);
// Sets editor options that control its final look
IEditorOptions? editorOptions = viewModel.WpfTextView.Properties.GetProperty(typeof(IEditorOptions)) as IEditorOptions;
if (editorOptions != null)
{
editorOptions.SetOptionValue("TextViewHost/ZoomControl", false);
editorOptions.SetOptionValue(DefaultWpfViewOptions.AppearanceCategory, AppearanceCategory);
}
Typeface typeface = new Typeface(container.FontFamily, container.FontStyle, container.FontWeight, container.FontStretch);
_classificationFormatMap.DefaultTextProperties = _classificationFormatMap.DefaultTextProperties.SetTypeface(typeface);
_classificationFormatMap.DefaultTextProperties = _classificationFormatMap.DefaultTextProperties.SetFontRenderingEmSize(container.FontSize);
ErrorHandler.ThrowOnFailure(viewModel.VsTextView.AddCommandFilter(this, out this._nextCommandTarget));
// Get the host control to render the view
this._textViewHost = _editorAdapterFactory.GetWpfTextViewHost(viewModel.VsTextView);
BindingOperations.SetBinding(_textViewHost.HostControl, AutomationProperties.NameProperty, new Binding { Source = container, Path = new PropertyPath(AutomationProperties.NameProperty) });
BindingOperations.SetBinding(_textViewHost.HostControl, AutomationProperties.LabeledByProperty, new Binding { Source = container, Path = new PropertyPath(AutomationProperties.LabeledByProperty) });
// For non-blurry text
TextOptions.SetTextFormattingMode(this._textViewHost.HostControl, TextFormattingMode.Display);
this._textViewHost.HostControl.Loaded += this.HostControl_Loaded;
this.AddLogicalChild(this._textViewHost.HostControl);
this.AddVisualChild(this._textViewHost.HostControl);
ContainerName = container.Name;
}
......@@ -63,17 +104,14 @@ public bool HasActiveIntellisenseSession
{
get
{
if (this._textViewHost != null)
if (this._textViewHost.TextView.Properties.TryGetProperty(typeof(ICompletionBroker), out ICompletionBroker completionBroker))
{
if (this._textViewHost.TextView.Properties.TryGetProperty(typeof(ICompletionBroker), out ICompletionBroker completionBroker))
{
return completionBroker.IsCompletionActive(this._textViewHost.TextView);
}
return completionBroker.IsCompletionActive(this._textViewHost.TextView);
}
if (this._textViewHost.TextView.Properties.TryGetProperty(typeof(IIntellisenseSessionStack), out IIntellisenseSessionStack intellisenseSessionStack))
{
return intellisenseSessionStack.Sessions.Count > 0;
}
if (this._textViewHost.TextView.Properties.TryGetProperty(typeof(IIntellisenseSessionStack), out IIntellisenseSessionStack intellisenseSessionStack))
{
return intellisenseSessionStack.Sessions.Count > 0;
}
return false;
......@@ -103,14 +141,7 @@ protected override int VisualChildrenCount
/// <param name="index">child index</param>
/// <returns>returns visual child</returns>
protected override Visual GetVisualChild(int index)
{
if (this._textViewHost != null)
{
return this._textViewHost.HostControl;
}
return null;
}
=> this._textViewHost.HostControl;
/// <summary>
/// Executes the given shell command
......@@ -139,7 +170,10 @@ public int Exec(ref Guid pguidCmdGroup, uint cmdID, uint cmdExecOpt, IntPtr pvaI
// 3. For other commands, simply return with NOTSUPPORTED
if (this.IsPassThroughCommand(ref pguidCmdGroup, cmdID))
{
hr = this._nextCommandTarget.Exec(ref pguidCmdGroup, cmdID, cmdExecOpt, pvaIn, pvaOut);
if (this._nextCommandTarget != null)
{
hr = this._nextCommandTarget.Exec(ref pguidCmdGroup, cmdID, cmdExecOpt, pvaIn, pvaOut);
}
}
else if ((pguidCmdGroup == VsMenus.guidStandardCommandSet97 && cmdID == StandardCommands.Cut.ID) ||
(pguidCmdGroup == VsMenus.guidStandardCommandSet2K && cmdID == (uint)VSConstants.VSStd2KCmdID.CUT))
......@@ -195,8 +229,13 @@ public int QueryStatus(ref Guid pguidCmdGroup, uint cmdCount, OLECMD[] prgCmds,
{
OLECMD[] cmdArray = new OLECMD[] { new OLECMD() };
cmdArray[0].cmdID = prgCmds[i].cmdID;
int hr = this._nextCommandTarget.QueryStatus(ref pguidCmdGroup, 1, cmdArray, cmdText);
if (this._nextCommandTarget == null)
{
continue;
}
int hr = this._nextCommandTarget.QueryStatus(ref pguidCmdGroup, 1, cmdArray, cmdText);
if (ErrorHandler.Failed(hr))
{
continue;
......@@ -242,11 +281,7 @@ public int QueryStatus(ref Guid pguidCmdGroup, uint cmdCount, OLECMD[] prgCmds,
/// <returns>return arrange size</returns>
protected override Size ArrangeOverride(Size finalSize)
{
if (this._textViewHost != null)
{
this._textViewHost.HostControl.Arrange(new Rect(new Point(0, 0), finalSize));
}
this._textViewHost.HostControl.Arrange(new Rect(new Point(0, 0), finalSize));
return finalSize;
}
......@@ -256,52 +291,6 @@ protected override void OnGotFocus(RoutedEventArgs e)
this._textViewHost.TextView.VisualElement.Focus();
}
/// <summary>
/// Initializes the editor control
/// </summary>
private void InitializeEditorControl(IntellisenseTextBoxViewModel viewModel, ContentControl container)
{
IComponentModel componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
// Sets editor options that control its final look
IEditorOptions editorOptions = viewModel.WpfTextView.Properties.GetProperty(typeof(IEditorOptions)) as IEditorOptions;
editorOptions.SetOptionValue("TextViewHost/ZoomControl", false);
editorOptions.SetOptionValue(DefaultWpfViewOptions.AppearanceCategory, AppearanceCategory);
// Set the font used in the editor
// The editor will automatically choose the font, color for the text
// depending on the current language. Override the font information
// to have uniform look and feel in the parallel watch window
IClassificationFormatMapService classificationFormatMapService = componentModel.GetService<IClassificationFormatMapService>();
IClassificationFormatMap classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap(AppearanceCategory);
Typeface typeface = new Typeface(container.FontFamily, container.FontStyle, container.FontWeight, container.FontStretch);
classificationFormatMap.DefaultTextProperties = classificationFormatMap.DefaultTextProperties.SetTypeface(typeface);
classificationFormatMap.DefaultTextProperties = classificationFormatMap.DefaultTextProperties.SetFontRenderingEmSize(container.FontSize);
// Install this object in the text view command filter chain
IEditorOperationsFactoryService editorOperationsFactoryService = componentModel.GetService<IEditorOperationsFactoryService>();
if (editorOperationsFactoryService != null)
{
this._editorOperations = editorOperationsFactoryService.GetEditorOperations(viewModel.WpfTextView);
}
ErrorHandler.ThrowOnFailure(viewModel.VsTextView.AddCommandFilter(this, out this._nextCommandTarget));
// Get the host control to render the view
IVsEditorAdaptersFactoryService editorAdapterFactory = componentModel.GetService<IVsEditorAdaptersFactoryService>();
this._textViewHost = editorAdapterFactory.GetWpfTextViewHost(viewModel.VsTextView);
BindingOperations.SetBinding(_textViewHost.HostControl, AutomationProperties.NameProperty, new Binding { Source = container, Path = new PropertyPath(AutomationProperties.NameProperty) });
BindingOperations.SetBinding(_textViewHost.HostControl, AutomationProperties.LabeledByProperty, new Binding { Source = container, Path = new PropertyPath(AutomationProperties.LabeledByProperty) });
// For non-blurry text
TextOptions.SetTextFormattingMode(this._textViewHost.HostControl, TextFormattingMode.Display);
this._textViewHost.HostControl.Loaded += this.HostControl_Loaded;
this.AddLogicalChild(this._textViewHost.HostControl);
this.AddVisualChild(this._textViewHost.HostControl);
}
/// <summary>
/// Event handler for editor control load
/// </summary>
......@@ -309,27 +298,21 @@ private void InitializeEditorControl(IntellisenseTextBoxViewModel viewModel, Con
/// <param name="e">Event args</param>
private void HostControl_Loaded(object sender, RoutedEventArgs e)
{
if (this._textViewHost != null)
{
// Set the focus
this._textViewHost.TextView.VisualElement.Focus();
// Set the focus
this._textViewHost.TextView.VisualElement.Focus();
if (this._textViewHost != null)
{
ITextSnapshot textSnapshot = this._textViewHost.TextView.TextSnapshot;
if (this.Text.IsNullOrWhiteSpace())
{
// Select all text in the control if edit is not started by user keyboard input
ITextSelection textSelection = this._textViewHost.TextView.Selection;
textSelection.Select(new SnapshotSpan(textSnapshot, 0, textSnapshot.Length), false);
}
else
{
// Otherwise Move to caret to end
ITextCaret textCaret = this._textViewHost.TextView.Caret;
textCaret.MoveTo(new SnapshotPoint(textSnapshot, textSnapshot.Length));
}
}
ITextSnapshot textSnapshot = this._textViewHost.TextView.TextSnapshot;
if (this.Text.IsNullOrWhiteSpace())
{
// Select all text in the control if edit is not started by user keyboard input
ITextSelection textSelection = this._textViewHost.TextView.Selection;
textSelection.Select(new SnapshotSpan(textSnapshot, 0, textSnapshot.Length), false);
}
else
{
// Otherwise Move to caret to end
ITextCaret textCaret = this._textViewHost.TextView.Caret;
textCaret.MoveTo(new SnapshotPoint(textSnapshot, textSnapshot.Length));
}
}
......@@ -339,18 +322,15 @@ private void HostControl_Loaded(object sender, RoutedEventArgs e)
/// <returns>True if cut and copy operation should be enabled</returns>
private bool CanCutCopy()
{
if (this._textViewHost != null)
{
ITextSelection textSelection = this._textViewHost.TextView.Selection;
ITextSelection textSelection = this._textViewHost.TextView.Selection;
if (textSelection.SelectedSpans != null && textSelection.SelectedSpans.Count > 0)
if (textSelection.SelectedSpans != null && textSelection.SelectedSpans.Count > 0)
{
foreach (SnapshotSpan snapshotSpan in textSelection.SelectedSpans)
{
foreach (SnapshotSpan snapshotSpan in textSelection.SelectedSpans)
if (snapshotSpan.Length > 0)
{
if (snapshotSpan.Length > 0)
{
return true;
}
return true;
}
}
}
......@@ -476,7 +456,7 @@ public bool HandleKeyDown(OLE.Interop.MSG message)
Guid editCmdGuid;
int VariantSize = 16;
IVsFilterKeys2 filterKeys = Package.GetGlobalService(typeof(SVsFilterKeys)) as IVsFilterKeys2;
IVsFilterKeys2? filterKeys = Package.GetGlobalService(typeof(SVsFilterKeys)) as IVsFilterKeys2;
if (filterKeys != null)
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Composition;
using System.Windows.Controls;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Operations;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls
{
[Export(typeof(IntellisenseTextBoxFactory)), Shared]
internal class IntellisenseTextBoxFactory
{
private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly IVsEditorAdaptersFactoryService _editorAdapterFactory;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public IntellisenseTextBoxFactory(
IEditorOperationsFactoryService editorOperationsFactoryService,
IClassificationFormatMapService classificationFormatMapService,
IVsEditorAdaptersFactoryService editorAdapterFactory)
{
_editorOperationsFactoryService = editorOperationsFactoryService;
// Set the font used in the editor
// The editor will automatically choose the font, color for the text
// depending on the current language. Override the font information
// to have uniform look and feel in the parallel watch window
_classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap(IntellisenseTextBox.AppearanceCategory);
_editorAdapterFactory = editorAdapterFactory;
}
public IntellisenseTextBox Create(IntellisenseTextBoxViewModel viewModel, ContentControl container)
=> new IntellisenseTextBox(_editorOperationsFactoryService, _classificationFormatMap, _editorAdapterFactory, viewModel, container);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
......@@ -31,8 +35,8 @@ internal class IntellisenseTextBoxViewModelFactory
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly ITextEditorFactoryService _textEditorFactoryService;
private readonly OLE.Interop.IServiceProvider _serviceProvider;
private readonly IProjectionBufferFactoryService _projectionBufferFactoryService;
private readonly SVsServiceProvider _services;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
......@@ -45,28 +49,45 @@ internal class IntellisenseTextBoxViewModelFactory
{
_editorAdaptersFactoryService = editorAdaptersFactoryService;
_textEditorFactoryService = textEditorFactoryService;
_serviceProvider = (OLE.Interop.IServiceProvider)services.GetService(typeof(OLE.Interop.IServiceProvider));
_services = services;
_projectionBufferFactoryService = projectionBufferFactoryService;
}
public IntellisenseTextBoxViewModel[] CreateIntellisenseTextBoxViewModels(
public async Task<IntellisenseTextBoxViewModel[]?> CreateIntellisenseTextBoxViewModelsAsync(
Document document,
IContentType contentType,
string contentString,
Func<ITextSnapshot, ITrackingSpan[]> createSpansMethod,
int insertPosition,
string textToInsert,
Func<ITextSnapshot, int, ITrackingSpan[]> createSpansMethod,
string[][] rolesCollections)
{
var vsTextLines = _editorAdaptersFactoryService.CreateVsTextBufferAdapter(_serviceProvider, contentType) as IVsTextLines;
var serviceProvider = (OLE.Interop.IServiceProvider)_services.GetService(typeof(OLE.Interop.IServiceProvider));
var syntaxTree = await document.GetSyntaxTreeAsync(CancellationToken.None).ConfigureAwait(false);
if (syntaxTree == null)
{
return null;
}
var sourceText = await syntaxTree.GetTextAsync(CancellationToken.None).ConfigureAwait(false);
var documentText = sourceText.ToString();
var contentString = documentText.Insert(insertPosition, textToInsert);
var vsTextLines = _editorAdaptersFactoryService.CreateVsTextBufferAdapter(serviceProvider, contentType) as IVsTextLines;
if (vsTextLines == null)
{
return null;
}
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);
new object[] { originalContextBuffer.CurrentSnapshot.CreateTrackingSpan(Span.FromBounds(0, originalContextBuffer.CurrentSnapshot.Length), SpanTrackingMode.EdgeInclusive) }, ProjectionBufferOptions.None, contentType);
// Make projection readonly so we can't edit it by mistake.
using (var regionEdit = contextBuffer.CreateReadOnlyRegionEdit())
......@@ -77,7 +98,7 @@ internal class IntellisenseTextBoxViewModelFactory
// Put it all into a projection buffer
var projectionBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
createSpansMethod(contextBuffer.CurrentSnapshot),
createSpansMethod(contextBuffer.CurrentSnapshot, insertPosition),
ProjectionBufferOptions.None, contentType);
// Fork the solution using this new primary buffer for the document and all of its linked documents.
......@@ -103,7 +124,7 @@ internal class IntellisenseTextBoxViewModelFactory
{
var roleSet = _textEditorFactoryService.CreateTextViewRoleSet(rolesCollections[i]);
var vsTextView = _editorAdaptersFactoryService.CreateVsTextViewAdapter(_serviceProvider, roleSet);
var vsTextView = _editorAdaptersFactoryService.CreateVsTextViewAdapter(serviceProvider, roleSet);
vsTextView.Initialize(
vsTextLines,
......@@ -111,7 +132,6 @@ internal class IntellisenseTextBoxViewModelFactory
(uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
s_InitViews);
// Here we need ITextViewModelProvider handling the corresponding role.
var wpfTextView = _editorAdaptersFactoryService.GetWpfTextView(vsTextView);
wpfTextView.TextBuffer.ChangeContentType(contentType, null);
......
// 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.VisualStudio.Text;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
internal static class ITextSnapshotExtensions
{
public static ITrackingSpan CreateFullTrackingSpan(this ITextSnapshot textSnapshot, SpanTrackingMode trackingMode)
{
return textSnapshot.CreateTrackingSpan(Span.FromBounds(0, textSnapshot.Length), trackingMode);
}
public static ITrackingSpan CreateTrackingSpanFromIndexToEnd(this ITextSnapshot textSnapshot, int index, SpanTrackingMode trackingMode)
{
return textSnapshot.CreateTrackingSpan(Span.FromBounds(index, textSnapshot.Length), trackingMode);
}
public static ITrackingSpan CreateTrackingSpanFromStartToIndex(this ITextSnapshot textSnapshot, int index, SpanTrackingMode trackingMode)
{
return textSnapshot.CreateTrackingSpan(Span.FromBounds(0, index), trackingMode);
}
}
}
......@@ -12,6 +12,7 @@ Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel
Imports Microsoft.VisualStudio.Text.Classification
Imports Roslyn.Test.Utilities
Imports Roslyn.Utilities
......@@ -371,7 +372,7 @@ class Test
Dim finalParameterList = actualParameterList.Where(Function(p) Not p.IsRemoved)
For index = 0 To permutation.Length - 1
Dim expected = originalParameterList(permutation(index))
Assert.Equal(expected, finalParameterList(index).ParameterSymbol)
Assert.Equal(expected, DirectCast(finalParameterList(index), ExistingParameterViewModel).ParameterSymbol)
Next
End Sub
......@@ -402,7 +403,7 @@ class Test
End If
If parameterName IsNot Nothing Then
Assert.Equal(parameterName, parameter.Parameter)
Assert.Equal(parameterName, parameter.ParameterName)
End If
If defaultValue IsNot Nothing Then
......@@ -441,7 +442,7 @@ class Test
Dim symbol = (Await workspaceDoc.GetSemanticModelAsync()).GetDeclaredSymbol(token.Parent)
Dim viewModel = New ChangeSignatureDialogViewModel(
ParameterConfiguration.Create(symbol.GetParameters().Select(Function(p) DirectCast(New ExistingParameter(p), Parameter)).ToList(), symbol.IsExtensionMethod(), selectedIndex:=0),
ParameterConfiguration.Create(symbol.GetParameters().Select(Function(p) DirectCast(New ExistingParameter(p), Parameter)), symbol.IsExtensionMethod(), selectedIndex:=0),
symbol,
workspaceDoc,
insertPosition:=0,
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Composition
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
Imports Microsoft.VisualStudio.LanguageServices.Implementation.IntellisenseControls
Imports Microsoft.VisualStudio.Text
Imports Microsoft.VisualStudio.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ChangeSignature
<ExportLanguageService(GetType(IChangeSignatureLanguageService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicChangeSignatureLanguageService
Inherits ChangeSignatureLanguageService
Public Overrides Function CreateViewModels(rolesCollectionType() As String,
rolesCollectionName() As String,
insertPosition As Integer, document As Document,
documentText As String, contentType As IContentType,
intellisenseTextBoxViewModelFactory As IntellisenseTextBoxViewModelFactory) As IntellisenseTextBoxViewModel()
Dim rolesCollections = {rolesCollectionName, rolesCollectionType}
' We insert '[]' so that we're always able to generate the type even if the name field is empty.
' We insert '~' to avoid Intellisense activation for the name field, since completion for names does not apply to VB.
Dim test = documentText.Insert(insertPosition, ", [~] As ")
Return intellisenseTextBoxViewModelFactory.CreateIntellisenseTextBoxViewModels(
document,
contentType,
documentText.Insert(insertPosition, ", [~] As "),
Function(snapshot As ITextSnapshot)
' + 4 to support inserted ', [~'
Return CreateTrackingSpansHelper(snapshot, contextPoint:=insertPosition + 4, spaceBetweenTypeAndName:=5)
End Function,
rolesCollections)
End Function
Public Overrides Sub GeneratePreviewDisplayParts(addedParameterViewModel As ChangeSignatureDialogViewModel.AddedParameterViewModel, displayParts As List(Of SymbolDisplayPart))
displayParts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.ParameterName, Nothing, addedParameterViewModel.Parameter))
displayParts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.Keyword, Nothing, " As " + addedParameterViewModel.Type))
End Sub
Public Overrides Function IsTypeNameValid(typeName As String) As Boolean
Return Not SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics
End Function
End Class
End Namespace
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Composition
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
Imports Microsoft.VisualStudio.Text
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ChangeSignature
<ExportLanguageService(GetType(IChangeSignatureViewModelFactoryService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicChangeSignatureViewModelFactoryService
Inherits ChangeSignatureViewModelFactoryService
Protected Overrides Function CreateSpansMethod(textSnapshot As ITextSnapshot, insertPosition As Integer) As ITrackingSpan()
' + 4 to support inserted ', [~'
Return CreateTrackingSpansHelper(textSnapshot, contextPoint:=insertPosition + 4, spaceBetweenTypeAndName:=5)
End Function
' We insert '[]' so that we're always able to generate the type even if the name field is empty.
' We insert '~' to avoid Intellisense activation for the name field, since completion for names does not apply to VB.
Protected Overrides ReadOnly Property TextToInsert As String
Get
Return ", [~] As "
End Get
End Property
Protected Overrides ReadOnly Property ContentTypeName As String
Get
Return ContentTypeNames.VisualBasicContentType
End Get
End Property
Public Overrides Function GeneratePreviewDisplayParts(addedParameterViewModel As ChangeSignatureDialogViewModel.AddedParameterViewModel) As SymbolDisplayPart()
Return {
New SymbolDisplayPart(SymbolDisplayPartKind.ParameterName, Nothing, addedParameterViewModel.ParameterName),
New SymbolDisplayPart(SymbolDisplayPartKind.Keyword, Nothing, " As " + addedParameterViewModel.Type)}
End Function
Public Overrides Function IsTypeNameValid(typeName As String) As Boolean
Return Not SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册