Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Xaml command hanler for CreateEventHandler command #51670

Merged
merged 4 commits into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;

namespace Microsoft.VisualStudio.LanguageServices.Xaml.Features.Commands
{
internal interface IXamlCommandService : ILanguageService
{
/// <summary>
/// Execute the <paramref name="command"/> with the <paramref name="commandArguments"/>
/// </summary>
/// <param name="document">TextDocument command was triggered on</param>
/// <param name="command">The command that will be executed</param>
/// <param name="commandArguments">The arguments need by the command</param>
/// <param name="cancellationToken">cancellationToken</param>
/// <returns>True if the command has been executed, otherwise false</returns>
Task<bool> ExecuteCommandAsync(TextDocument document, string command, object[]? commandArguments, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ internal class XamlCompletionItem
public ClassifiedTextElement Description { get; set; }
public ImageElement Icon { get; set; }
public ISymbol Symbol { get; set; }
public XamlEventDescription? EventDescription { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;

namespace Microsoft.VisualStudio.LanguageServices.Xaml.Features.Completion
{
internal struct XamlEventDescription
{
public string ClassName { get; set; }
public string EventName { get; set; }
public string ReturnType { get; set; }
public ImmutableArray<(string Name, string ParameterType, string Modifier)> Parameters { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.Editor.Xaml;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler;

Expand All @@ -28,6 +29,7 @@ internal static class XamlCapabilities
},
SupportsDiagnosticRequests = true,
OnTypeRenameProvider = new DocumentOnTypeRenameOptions { WordPattern = OnTypeRenameHandler.NamePattern },
ExecuteCommandProvider = new ExecuteCommandOptions { Commands = new[] { StringConstants.CreateEventHandlerCommand } },
};

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Xaml;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.Xaml.Features.Commands;
using Microsoft.VisualStudio.LanguageServices.Xaml.Features.Completion;
using Newtonsoft.Json.Linq;
using Roslyn.Utilities;

namespace Microsoft.VisualStudio.LanguageServices.Xaml.Implementation.LanguageServer.Handler.Commands
{
/// <summary>
/// Handle the command that adds an event handler method in code
/// </summary>
internal class CreateEventCommandHandler : AbstractExecuteWorkspaceCommandHandler
{
public override string Command => StringConstants.CreateEventHandlerCommand;

public override bool MutatesSolutionState => false;

public override bool RequiresLSPSolution => true;

public override TextDocumentIdentifier? GetTextDocumentIdentifier(ExecuteCommandParams request)
=> ((JToken)request.Arguments.First()).ToObject<TextDocumentIdentifier>();

public override async Task<object> HandleRequestAsync(ExecuteCommandParams request, RequestContext context, CancellationToken cancellationToken)
{
Contract.ThrowIfNull(request.Arguments);

var document = context.Document;
if (document == null)
{
return false;
}

var commandService = document.Project.LanguageServices.GetService<IXamlCommandService>();
if (commandService == null)
{
return false;
}

// request.Arguments has two argument for CreateEventHandlerCommand
// Arguments[0]: TextDocumentIdentifier
// Arguments[1]: XamlEventDescription
var arguments = new object[] { ((JToken)request.Arguments[1]).ToObject<XamlEventDescription>() };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see arguments[0] being used anywhere, do we actually need that item?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it is used in line 29 GetTextDocumentIdentifier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I missed that. It looks like if we get the command it must have that argument, so I'd recommend First()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me.

return await commandService.ExecuteCommandAsync(document, request.Command, arguments, cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Editor.Xaml;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands;

namespace Microsoft.VisualStudio.LanguageServices.Xaml.Implementation.LanguageServer.Handler.Commands
{
[ExportLspRequestHandlerProvider(StringConstants.XamlLanguageName), Shared]
[ProvidesCommand(StringConstants.CreateEventHandlerCommand)]
internal class CreateEventCommandHandlerProvider : AbstractRequestHandlerProvider
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CreateEventCommandHandlerProvider()
{
}

Copy link
Contributor

@mgoertz-msft mgoertz-msft Mar 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually needed? We're not importing anything in here. #Closed

Copy link
Contributor Author

@LinglingTong LinglingTong Mar 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required by the ExportLspRequestHandlerProvider. I will get warning if I don't have an importing constructor. #Closed

public override ImmutableArray<IRequestHandler> CreateRequestHandlers()
{
return ImmutableArray.Create<IRequestHandler>(new CreateEventCommandHandler());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler
internal class CompletionHandler : AbstractStatelessRequestHandler<CompletionParams, CompletionList?>
{
public override string Method => Methods.TextDocumentCompletionName;
private const string CreateEventHandlerCommandTitle = "Create Event Handler";

public override bool MutatesSolutionState => false;
public override bool RequiresLSPSolution => true;
Expand Down Expand Up @@ -58,12 +59,12 @@ public CompletionHandler()

return new VSCompletionList
{
Items = completionResult.Completions.Select(c => CreateCompletionItem(c, document.Id, text, request.Position)).ToArray(),
Items = completionResult.Completions.Select(c => CreateCompletionItem(c, document.Id, text, request.Position, request.TextDocument)).ToArray(),
SuggestionMode = false,
};
}

private static CompletionItem CreateCompletionItem(XamlCompletionItem xamlCompletion, DocumentId documentId, SourceText text, Position position)
private static CompletionItem CreateCompletionItem(XamlCompletionItem xamlCompletion, DocumentId documentId, SourceText text, Position position, TextDocumentIdentifier textDocument)
{
var item = new VSCompletionItem
{
Expand All @@ -89,6 +90,16 @@ private static CompletionItem CreateCompletionItem(XamlCompletionItem xamlComple
};
}

if (xamlCompletion.EventDescription.HasValue)
{
item.Command = new Command()
{
CommandIdentifier = StringConstants.CreateEventHandlerCommand,
Arguments = new object[] { textDocument, xamlCompletion.EventDescription },
Title = CreateEventHandlerCommandTitle
};
}

return item;
}

Expand Down
2 changes: 2 additions & 0 deletions src/VisualStudio/Xaml/Impl/StringConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ internal static class StringConstants
public const string XamlFileExtension = ".xaml";

public const string EnableLspIntelliSense = "Xaml.EnableLspIntelliSense";

public const string CreateEventHandlerCommand = "Xaml.CreateEventHandler";
}
}