зеркало из https://github.com/dotnet/razor.git
Initial implementation of WrapWithDiv command
This commit is contained in:
Родитель
b0b810421f
Коммит
b7b7611a2d
|
@ -2,7 +2,7 @@
|
|||
<!-- Opt-in arcade features -->
|
||||
<PropertyGroup>
|
||||
<UsingToolVSSDK>true</UsingToolVSSDK>
|
||||
<MicrosoftVSSDKBuildToolsVersion>17.0.63-dev17-g3f11f5ab</MicrosoftVSSDKBuildToolsVersion>
|
||||
<MicrosoftVSSDKBuildToolsVersion>17.0.5232</MicrosoftVSSDKBuildToolsVersion>
|
||||
<MicroBuildPluginsSwixBuildVersion>1.1.33</MicroBuildPluginsSwixBuildVersion>
|
||||
<!-- Use .NET Framework reference assemblies from a nuget package so machine-global targeting packs do not need to be installed. -->
|
||||
<UsingToolNetFrameworkReferenceAssemblies>true</UsingToolNetFrameworkReferenceAssemblies>
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common
|
|||
|
||||
public const string RazorServerReadyEndpoint = "razor/serverReady";
|
||||
|
||||
public const string RazorWrapWithTagEndpoint = "razor/wrapWithTag";
|
||||
|
||||
public static class CodeActions
|
||||
{
|
||||
public const string EditBasedCodeActionCommand = "EditBasedCodeActionCommand";
|
||||
|
|
|
@ -130,6 +130,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
|
|||
.WithHandler<RazorComponentRenameEndpoint>()
|
||||
.WithHandler<RazorDefinitionEndpoint>()
|
||||
.WithHandler<LinkedEditingRangeEndpoint>()
|
||||
.WithHandler<WrapWithTagEndpoint>()
|
||||
.WithServices(services =>
|
||||
{
|
||||
services.AddLogging(builder => builder
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv;
|
||||
using OmniSharp.Extensions.JsonRpc;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert
|
||||
{
|
||||
[Parallel, Method(LanguageServerConstants.RazorWrapWithTagEndpoint)]
|
||||
internal interface IWrapWithTagHandler : IJsonRpcRequestHandler<WrapWithTagParams, WrapWithTagResponse>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common.Extensions;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert
|
||||
{
|
||||
internal class WrapWithTagEndpoint : IWrapWithTagHandler
|
||||
{
|
||||
private readonly ClientNotifierServiceBase _languageServer;
|
||||
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
|
||||
private readonly DocumentResolver _documentResolver;
|
||||
private readonly RazorDocumentMappingService _razorDocumentMappingService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public WrapWithTagEndpoint(
|
||||
ClientNotifierServiceBase languageServer,
|
||||
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
|
||||
DocumentResolver documentResolver,
|
||||
RazorDocumentMappingService razorDocumentMappingService,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (languageServer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(languageServer));
|
||||
}
|
||||
|
||||
if (projectSnapshotManagerDispatcher is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
|
||||
}
|
||||
|
||||
if (documentResolver is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentResolver));
|
||||
}
|
||||
|
||||
if (razorDocumentMappingService is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(razorDocumentMappingService));
|
||||
}
|
||||
|
||||
if (loggerFactory is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_languageServer = languageServer;
|
||||
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
|
||||
_documentResolver = documentResolver;
|
||||
_razorDocumentMappingService = razorDocumentMappingService;
|
||||
_logger = loggerFactory.CreateLogger<WrapWithTagEndpoint>();
|
||||
}
|
||||
|
||||
public async Task<WrapWithTagResponse> Handle(WrapWithTagParams request, CancellationToken cancellationToken)
|
||||
{
|
||||
var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
|
||||
{
|
||||
_documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot);
|
||||
|
||||
return documentSnapshot;
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (documentSnapshot is null || cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogWarning($"Failed to find document {request.TextDocument.Uri}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var codeDocument = await documentSnapshot.GetGeneratedOutputAsync();
|
||||
if (codeDocument.IsUnsupported())
|
||||
{
|
||||
_logger.LogWarning($"Failed to retrieve generated output for document {request.TextDocument.Uri}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var sourceText = await documentSnapshot.GetTextAsync().ConfigureAwait(false);
|
||||
if (!request.Range.Start.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex);
|
||||
if (languageKind is not RazorLanguageKind.Html)
|
||||
{
|
||||
_logger.LogInformation($"Unsupported language {languageKind:G}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var parameter = request;
|
||||
var response = await _languageServer.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, parameter);
|
||||
var htmlResponse = await response.Returning<WrapWithTagResponse>(cancellationToken);
|
||||
|
||||
return htmlResponse;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing the parameters sent for a textDocument/_vsweb_wrapWithTag request.
|
||||
/// </summary>
|
||||
internal class WrapWithTagParams : ITextDocumentIdentifierParams, IRequest<WrapWithTagResponse>, IBaseRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the identifier for the text document to be operate on.
|
||||
/// </summary>
|
||||
[JsonProperty("_vs_textDocument")]
|
||||
public TextDocumentIdentifier TextDocument
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selection range to be wrapped.
|
||||
/// </summary>
|
||||
[JsonProperty("_vs_range")]
|
||||
public Range Range
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the wrapping tag name.
|
||||
/// </summary>
|
||||
[JsonProperty("_vs_tagName")]
|
||||
public string TagName
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting options.
|
||||
/// </summary>
|
||||
[JsonProperty("_vs_options")]
|
||||
public FormattingOptions Options
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing the response of an WrapWithTag response.
|
||||
/// </summary>
|
||||
internal class WrapWithTagResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the range of the wrapping tag.
|
||||
/// </summary>
|
||||
[JsonProperty("_vs_tagRange")]
|
||||
public Range TagRange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text edits.
|
||||
/// </summary>
|
||||
[JsonProperty("_vs_textEdits")]
|
||||
public TextEdit[] TextEdits { get; set; }
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ using Microsoft.VisualStudio.LanguageServer.ContainedLanguage.Extensions;
|
|||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.Extensions;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OmniSharpConfigurationParams = OmniSharp.Extensions.LanguageServer.Protocol.Models.ConfigurationParams;
|
||||
|
@ -475,5 +476,52 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor
|
|||
|
||||
return Task.FromResult(result.ToArray());
|
||||
}
|
||||
|
||||
public override async Task<VSInternalWrapWithTagResponse> RazorWrapWithTagAsync(VSInternalWrapWithTagParams wrapWithParams, CancellationToken cancellationToken)
|
||||
{
|
||||
const string HtmlWrapWithTagEndpoint = "textDocument/_vsweb_wrapWithTag";
|
||||
|
||||
var response = new VSInternalWrapWithTagResponse(wrapWithParams.Range, Array.Empty<TextEdit>());
|
||||
|
||||
var hostDocumentUri = wrapWithParams.TextDocument.Uri;
|
||||
if (!_documentManager.TryGetDocument(hostDocumentUri, out var documentSnapshot))
|
||||
{
|
||||
return response;
|
||||
}
|
||||
|
||||
string languageServerName;
|
||||
Uri projectedUri;
|
||||
if (documentSnapshot.TryGetVirtualDocument<HtmlVirtualDocumentSnapshot>(out var htmlDocument))
|
||||
{
|
||||
languageServerName = RazorLSPConstants.HtmlLanguageServerName;
|
||||
projectedUri = htmlDocument.Uri;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Fail("Unexpected RazorLanguageKind. This can't really happen in a real scenario.");
|
||||
return response;
|
||||
}
|
||||
|
||||
var request = new VSInternalWrapWithTagParams(
|
||||
wrapWithParams.Range,
|
||||
wrapWithParams.TagName,
|
||||
wrapWithParams.Options,
|
||||
new TextDocumentIdentifier() { Uri = projectedUri });
|
||||
|
||||
var textBuffer = htmlDocument.Snapshot.TextBuffer;
|
||||
var result = await _requestInvoker.ReinvokeRequestOnServerAsync<VSInternalWrapWithTagParams, VSInternalWrapWithTagResponse>(
|
||||
textBuffer,
|
||||
HtmlWrapWithTagEndpoint,
|
||||
languageServerName,
|
||||
request,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result?.Response is not null)
|
||||
{
|
||||
response = result.Response;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Common;
|
|||
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic.Models;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv;
|
||||
using StreamJsonRpc;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor
|
||||
|
@ -52,5 +53,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor
|
|||
|
||||
[JsonRpcMethod(LanguageServerConstants.RazorServerReadyEndpoint, UseSingleObjectParameterDeserialization = true)]
|
||||
public abstract Task RazorServerReadyAsync(CancellationToken cancellationToken);
|
||||
|
||||
// Called by the Visual Studio to wrap the current selection with a tag
|
||||
[JsonRpcMethod(LanguageServerConstants.RazorWrapWithTagEndpoint, UseSingleObjectParameterDeserialization = true)]
|
||||
public abstract Task<VSInternalWrapWithTagResponse> RazorWrapWithTagAsync(VSInternalWrapWithTagParams wrapWithParams, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Runtime.Serialization;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing the parameters sent for a textDocument/_vsweb_wrapWithTag request.
|
||||
/// Matches corresponding class in Web Tools' Html language server
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
internal class VSInternalWrapWithTagParams
|
||||
{
|
||||
public VSInternalWrapWithTagParams(Range range,
|
||||
string tagName,
|
||||
FormattingOptions options,
|
||||
TextDocumentIdentifier textDocument)
|
||||
{
|
||||
Range = range;
|
||||
Options = options;
|
||||
TagName = tagName;
|
||||
TextDocument = textDocument;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the identifier for the text document to be operate on.
|
||||
/// </summary>
|
||||
[DataMember(Name = "_vs_textDocument")]
|
||||
public TextDocumentIdentifier TextDocument
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selection range to be wrapped.
|
||||
/// </summary>
|
||||
[DataMember(Name = "_vs_range")]
|
||||
public Range Range
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the wrapping tag name.
|
||||
/// </summary>
|
||||
[DataMember(Name = "_vs_tagName")]
|
||||
public string TagName
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting options.
|
||||
/// </summary>
|
||||
[DataMember(Name = "_vs_options")]
|
||||
public FormattingOptions Options
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Runtime.Serialization;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing the response of an WrapWithTag response.
|
||||
/// Matches corresponding class in Web Tools' Html language server
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
internal class VSInternalWrapWithTagResponse
|
||||
{
|
||||
public VSInternalWrapWithTagResponse(Range tagRange, TextEdit[] textEdits)
|
||||
{
|
||||
TagRange = tagRange;
|
||||
TextEdits = textEdits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the range of the wrapping tag.
|
||||
/// </summary>
|
||||
[DataMember(Name = "_vs_tagRange")]
|
||||
public Range TagRange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text edits.
|
||||
/// </summary>
|
||||
[DataMember(Name = "_vs_textEdits")]
|
||||
public TextEdit[] TextEdits
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
|
||||
using Microsoft.VisualStudio.Commanding;
|
||||
using Microsoft.VisualStudio.Editor.Commanding;
|
||||
using Microsoft.VisualStudio.LanguageServer.ContainedLanguage;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
using Microsoft.VisualStudio.LanguageServerClient.Razor.Extensions;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Editor;
|
||||
using Microsoft.VisualStudio.Text.Editor.Commanding;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Microsoft.VisualStudio.Utilities;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.WrapWithDiv
|
||||
{
|
||||
[Export(typeof(ICommandHandler))]
|
||||
[ContentType(RazorLSPConstants.RazorLSPContentTypeName)]
|
||||
[Name(nameof(WrapWithDivCommandHandler))]
|
||||
internal sealed class WrapWithDivCommandHandler : ICommandHandler<WrapWithDivCommandArgs>
|
||||
{
|
||||
private readonly LSPRequestInvoker _requestInvoker;
|
||||
private readonly JoinableTaskFactory _jtf;
|
||||
private readonly ITextDocumentFactoryService _textDocumentFactoryService;
|
||||
private readonly FormattingOptionsProvider _formattingOptionsProvider;
|
||||
|
||||
public string DisplayName => nameof(WrapWithDivCommandHandler);
|
||||
|
||||
[ImportingConstructor]
|
||||
public WrapWithDivCommandHandler(
|
||||
LSPRequestInvoker requestInvoker,
|
||||
JoinableTaskContext joinableTaskContext,
|
||||
ITextDocumentFactoryService textDocumentFactoryService,
|
||||
FormattingOptionsProvider formattingOptionsProvider)
|
||||
{
|
||||
_requestInvoker = requestInvoker;
|
||||
_jtf = joinableTaskContext.Factory;
|
||||
_textDocumentFactoryService = textDocumentFactoryService;
|
||||
_formattingOptionsProvider = formattingOptionsProvider;
|
||||
}
|
||||
public CommandState GetCommandState(WrapWithDivCommandArgs args)
|
||||
{
|
||||
if (!args.SubjectBuffer.IsRazorLSPBuffer())
|
||||
{
|
||||
return CommandState.Unavailable;
|
||||
}
|
||||
|
||||
return CommandState.Available;
|
||||
}
|
||||
|
||||
public bool ExecuteCommand(WrapWithDivCommandArgs args, CommandExecutionContext executionContext)
|
||||
{
|
||||
var buffer = args.SubjectBuffer;
|
||||
var snapshot = buffer.CurrentSnapshot;
|
||||
var viewSpanToWrap = args.TextView.Selection.StreamSelectionSpan.SnapshotSpan;
|
||||
|
||||
// Handle projection view scenarios (eg: Tools.DiffFiles inline)
|
||||
var mappedSpansToWrap = args.TextView.BufferGraph.MapDownToBuffer(viewSpanToWrap, SpanTrackingMode.EdgeInclusive, buffer);
|
||||
|
||||
if (mappedSpansToWrap.Count != 1)
|
||||
{
|
||||
// The selection spanned multiple buffers, not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: It's important to not use a jtf.Run here to try to achieve synchronous behavioe. JsonRPC doesn't carry over the
|
||||
// synchronization context, which means unresponsiveness will occur if if the inproc json handler on the other side attempts to
|
||||
// do a jtf.SwitchToMainThread.
|
||||
// Also, intentionally not using IUIThreadOperationExecutor to bring up the wait dialog as there would be interweaved
|
||||
// creation/disposal of these objects since vs's commanding infrastructure creates/disposes an instance around their
|
||||
// call into this handler.
|
||||
_ = _jtf.RunAsync(async () =>
|
||||
{
|
||||
var result = await InvokeWrapWithDivAsync(snapshot, mappedSpansToWrap[0], buffer);
|
||||
|
||||
if (result is not null && result.TextEdits.Length > 0)
|
||||
{
|
||||
ApplyChanges(snapshot, result, args.TextView);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<VSInternalWrapWithTagResponse?> InvokeWrapWithDivAsync(ITextSnapshot snapshot, SnapshotSpan spanToWrap, ITextBuffer subjectBuffer)
|
||||
{
|
||||
if (!_textDocumentFactoryService.TryGetTextDocument(subjectBuffer, out var document) ||
|
||||
document?.FilePath is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hostUri = new Uri(document.FilePath);
|
||||
|
||||
var wrapWithTagParams = new VSInternalWrapWithTagParams(
|
||||
range: spanToWrap.AsRange(),
|
||||
tagName: "div",
|
||||
options: _formattingOptionsProvider.GetOptions(hostUri),
|
||||
textDocument: new TextDocumentIdentifier() { Uri = hostUri }
|
||||
);
|
||||
|
||||
// Send the WrapWithTag request to the appropriate language server.
|
||||
var wrapWithTagResponse = await _requestInvoker.ReinvokeRequestOnServerAsync<VSInternalWrapWithTagParams, VSInternalWrapWithTagResponse>(
|
||||
subjectBuffer,
|
||||
LanguageServerConstants.RazorWrapWithTagEndpoint,
|
||||
RazorLSPConstants.RazorLanguageServerName,
|
||||
wrapWithTagParams,
|
||||
CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return wrapWithTagResponse?.Response;
|
||||
}
|
||||
|
||||
private static void ApplyChanges(ITextSnapshot snapshot, VSInternalWrapWithTagResponse wrapWithTagResponse, ITextView? textView = null)
|
||||
{
|
||||
// Make sure we're still looking at the same snapshot before we try to change anything
|
||||
if (snapshot != snapshot.TextBuffer.CurrentSnapshot)
|
||||
{
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var buffer = snapshot.TextBuffer;
|
||||
using var edit = buffer.CreateEdit();
|
||||
foreach (var curEdit in wrapWithTagResponse.TextEdits)
|
||||
{
|
||||
if (ToSnapshotSpan(curEdit.Range, snapshot) is SnapshotSpan currentSpan)
|
||||
{
|
||||
edit.Replace(currentSpan.Start, currentSpan.Length, curEdit.NewText);
|
||||
}
|
||||
}
|
||||
|
||||
var newSnapshot = edit.Apply();
|
||||
|
||||
if (textView is not null && ToSnapshotSpan(wrapWithTagResponse.TagRange, snapshot) is SnapshotSpan newSelection)
|
||||
{
|
||||
var bufferNewSelection = new SnapshotSpan(newSnapshot, newSelection);
|
||||
var newSelectionsInView = textView.BufferGraph.MapUpToBuffer(bufferNewSelection, SpanTrackingMode.EdgeInclusive, textView.TextBuffer);
|
||||
|
||||
if (newSelectionsInView.Count == 1)
|
||||
{
|
||||
textView.Selection.Select(newSelectionsInView[0], true);
|
||||
textView.Caret.MoveTo(textView.Selection.Start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int? GetPositionFromLineColumn(ITextSnapshot snapshot, int line, int column)
|
||||
{
|
||||
if ((line >= 0) && (line < snapshot.LineCount))
|
||||
{
|
||||
var textLine = snapshot.GetLineFromLineNumber(line);
|
||||
|
||||
// Non-strict equality below, because caret can be position *after*
|
||||
// the last character of the line. So for line of length 1 both
|
||||
// column 0 and column 1 are valid caret locations.
|
||||
if (column <= textLine.Length)
|
||||
{
|
||||
return textLine.Start + column;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SnapshotSpan? ToSnapshotSpan(Range range, ITextSnapshot snapshot)
|
||||
{
|
||||
if (ToSnapshotPoint(range.Start, snapshot) is SnapshotPoint startPoint &&
|
||||
ToSnapshotPoint(range.End, snapshot) is SnapshotPoint endPoint)
|
||||
{
|
||||
return new SnapshotSpan(startPoint, endPoint);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SnapshotPoint? ToSnapshotPoint(Position position, ITextSnapshot snapshot)
|
||||
{
|
||||
if (GetPositionFromLineColumn(snapshot, position.Line, position.Character) is int positionIndex)
|
||||
{
|
||||
return new SnapshotPoint(snapshot, positionIndex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
|
||||
internal class WrapWithDivCommandBindings
|
||||
{
|
||||
// These values match those in RazorContextMenu.vsct
|
||||
internal const string GuidRazorGroupString = "a3a603a2-2b17-4ce2-bd21-cbb8ccc084ec";
|
||||
internal const uint CmdIDWrapWithDiv = 0x101;
|
||||
|
||||
// This exports this command handler to handle the menu item defined in the vsct file
|
||||
[Export]
|
||||
[CommandBinding(GuidRazorGroupString, CmdIDWrapWithDiv, typeof(WrapWithDivCommandArgs))]
|
||||
internal CommandBindingDefinition wrapWithDivCommandBinding;
|
||||
}
|
||||
|
||||
// EditorCommandArgs is abstract, so we need to subclass it, but we have no value to add
|
||||
internal class WrapWithDivCommandArgs : EditorCommandArgs
|
||||
{
|
||||
public WrapWithDivCommandArgs(ITextView textView, ITextBuffer subjectBuffer)
|
||||
: base(textView, subjectBuffer)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
<ExcludeFromSourceBuild>true</ExcludeFromSourceBuild>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
|
||||
<GenerateResourceUsePreserializedResources Condition="'$(MSBuildRuntimeType)' == 'Core'">true</GenerateResourceUsePreserializedResources>
|
||||
|
||||
<SetupProductArch>neutral</SetupProductArch>
|
||||
<ServiceHubCoreSubPath>ServiceHubCore</ServiceHubCoreSubPath>
|
||||
|
@ -42,6 +42,12 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<VSCTCompile Include="RazorContextMenu.vsct">
|
||||
<ResourceName>Menus.ctmenu</ResourceName>
|
||||
</VSCTCompile>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Misc other content -->
|
||||
<ItemGroup>
|
||||
<Content Include="NOTICE.txt">
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable">
|
||||
|
||||
<Extern href="stdidcmd.h"/>
|
||||
<Extern href="vsshlids.h"/>
|
||||
|
||||
<Commands package="RazorPackage">
|
||||
|
||||
<Buttons>
|
||||
<Button guid="guidRazorGroup" id="cmdidRazorWrapWithDiv" priority="0x0100" type="Button">
|
||||
<Parent guid="guidSHLMainMenu" id="IDG_VS_CODEWIN_SNIPPETS" />
|
||||
<!-- This tells VS we want to control visibility at runtime -->
|
||||
<CommandFlag>DynamicVisibility</CommandFlag>
|
||||
<!-- This prevents the menu item showing up where QueryStatus doesn't tell it to -->
|
||||
<CommandFlag>DefaultInvisible</CommandFlag>
|
||||
<!-- This prevents the menu item showing up in the main menu -->
|
||||
<CommandFlag>CommandWellOnly</CommandFlag>
|
||||
<Strings>
|
||||
<ButtonText>Wrap With <div></ButtonText>
|
||||
</Strings>
|
||||
</Button>
|
||||
</Buttons>
|
||||
|
||||
</Commands>
|
||||
|
||||
<KeyBindings>
|
||||
<KeyBinding guid="guidRazorGroup" id="cmdidRazorWrapWithDiv" mod1="ALT SHIFT" key1="W" editor="guidVSStd97" />
|
||||
</KeyBindings>
|
||||
|
||||
<Symbols>
|
||||
<GuidSymbol name="RazorPackage" value="{13b72f58-279e-49e0-a56d-296be02f0805}" />
|
||||
|
||||
<GuidSymbol name="guidRazorGroup" value ="{a3a603a2-2b17-4ce2-bd21-cbb8ccc084ec}">
|
||||
<IDSymbol name="cmdidRazorWrapWithDiv" value="0x0101"/>
|
||||
</GuidSymbol>
|
||||
</Symbols>
|
||||
</CommandTable>
|
|
@ -26,6 +26,7 @@ namespace Microsoft.VisualStudio.RazorExtension
|
|||
[ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider64S", Audience = ServiceAudience.Local)]
|
||||
[ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProviderCore64", ServiceLocation = ProvideBrokeredServiceHubServiceAttribute.DefaultServiceLocation + @"\ServiceHubCore", Audience = ServiceAudience.Local)]
|
||||
[ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProviderCore64S", ServiceLocation = ProvideBrokeredServiceHubServiceAttribute.DefaultServiceLocation + @"\ServiceHubCore", Audience = ServiceAudience.Local)]
|
||||
[ProvideMenuResource("Menus.ctmenu", 1)]
|
||||
[Guid(PackageGuidString)]
|
||||
public sealed class RazorPackage : AsyncPackage
|
||||
{
|
||||
|
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.cs.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.cs.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="cs" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.de.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.de.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="de" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.es.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.es.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="es" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.fr.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.fr.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="fr" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.it.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.it.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="it" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.ja.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.ja.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="ja" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.ko.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.ko.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="ko" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.pl.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.pl.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="pl" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.pt-BR.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.pt-BR.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="pt-BR" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.ru.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.ru.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="ru" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.tr.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.tr.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="tr" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.zh-Hans.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.zh-Hans.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="zh-Hans" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.zh-Hant.xlf
сгенерированный
Normal file
12
src/Razor/src/Microsoft.VisualStudio.RazorExtension/xlf/RazorContextMenu.vsct.zh-Hant.xlf
сгенерированный
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
|
||||
<file datatype="xml" source-language="en" target-language="zh-Hant" original="../RazorContextMenu.vsct">
|
||||
<body>
|
||||
<trans-unit id="cmdidRazorWrapWithDiv|ButtonText">
|
||||
<source>Wrap With <div></source>
|
||||
<target state="new">Wrap With <div></target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
Загрузка…
Ссылка в новой задаче