|
// 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.
#nullable disable
using System;
using System.Diagnostics;
using Microsoft.VisualStudio.InteractiveWindow;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
using System.Threading;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Text.Editor.Commanding;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Interactive
{
internal abstract class InteractiveCommandHandler :
ICommandHandler<ExecuteInInteractiveCommandArgs>,
ICommandHandler<CopyToInteractiveCommandArgs>
{
private readonly EditorOptionsService _editorOptionsService;
private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
protected InteractiveCommandHandler(
IContentTypeRegistryService contentTypeRegistryService,
EditorOptionsService editorOptionsService,
IEditorOperationsFactoryService editorOperationsFactoryService)
{
ContentTypeRegistryService = contentTypeRegistryService;
_editorOptionsService = editorOptionsService;
_editorOperationsFactoryService = editorOperationsFactoryService;
}
protected IContentTypeRegistryService ContentTypeRegistryService { get; }
protected abstract IInteractiveWindow OpenInteractiveWindow(bool focus);
protected abstract ISendToInteractiveSubmissionProvider SendToInteractiveSubmissionProvider { get; }
public string DisplayName => EditorFeaturesResources.Interactive;
private string GetSelectedText(EditorCommandArgs args, CancellationToken cancellationToken)
{
var editorOptions = _editorOptionsService.Factory.GetOptions(args.SubjectBuffer);
return SendToInteractiveSubmissionProvider.GetSelectedText(editorOptions, args, cancellationToken);
}
CommandState ICommandHandler<ExecuteInInteractiveCommandArgs>.GetCommandState(ExecuteInInteractiveCommandArgs args)
=> CommandState.Available;
bool ICommandHandler<ExecuteInInteractiveCommandArgs>.ExecuteCommand(ExecuteInInteractiveCommandArgs args, CommandExecutionContext context)
{
var window = OpenInteractiveWindow(focus: false);
using (context.OperationContext.AddScope(allowCancellation: true, EditorFeaturesWpfResources.Executing_selection_in_Interactive_Window))
{
var submission = GetSelectedText(args, context.OperationContext.UserCancellationToken);
if (!string.IsNullOrWhiteSpace(submission))
{
window.SubmitAsync([submission]);
}
}
return true;
}
CommandState ICommandHandler<CopyToInteractiveCommandArgs>.GetCommandState(CopyToInteractiveCommandArgs args)
=> CommandState.Available;
bool ICommandHandler<CopyToInteractiveCommandArgs>.ExecuteCommand(CopyToInteractiveCommandArgs args, CommandExecutionContext context)
{
var window = OpenInteractiveWindow(focus: true);
var buffer = window.CurrentLanguageBuffer;
if (buffer != null)
{
CopyToWindow(window, args, context);
}
else
{
Action action = null;
action = new Action(() =>
{
window.ReadyForInput -= action;
CopyToWindow(window, args, context);
});
window.ReadyForInput += action;
}
return true;
}
private void CopyToWindow(IInteractiveWindow window, CopyToInteractiveCommandArgs args, CommandExecutionContext context)
{
var buffer = window.CurrentLanguageBuffer;
Debug.Assert(buffer != null);
using (var edit = buffer.CreateEdit())
using (var waitScope = context.OperationContext.AddScope(allowCancellation: true,
EditorFeaturesWpfResources.Copying_selection_to_Interactive_Window))
{
var text = GetSelectedText(args, context.OperationContext.UserCancellationToken);
// If the last line isn't empty in the existing submission buffer, we will prepend a
// newline
var lastLine = buffer.CurrentSnapshot.GetLineFromLineNumber(buffer.CurrentSnapshot.LineCount - 1);
if (lastLine.Extent.Length > 0)
{
var editorOptions = _editorOptionsService.Factory.GetOptions(args.SubjectBuffer);
text = editorOptions.GetNewLineCharacter() + text;
}
edit.Insert(buffer.CurrentSnapshot.Length, text);
edit.Apply();
}
// Move the caret to the end
var editorOperations = _editorOperationsFactoryService.GetEditorOperations(window.TextView);
var endPoint = new VirtualSnapshotPoint(window.TextView.TextBuffer.CurrentSnapshot, window.TextView.TextBuffer.CurrentSnapshot.Length);
editorOperations.SelectAndMoveCaret(endPoint, endPoint);
}
}
}
|