File: OutOfProcess\Editor_OutOfProc.cs
Web Access
Project: ..\..\..\src\VisualStudio\IntegrationTest\TestUtilities\Microsoft.VisualStudio.IntegrationTest.Utilities.csproj (Microsoft.VisualStudio.IntegrationTest.Utilities)
// 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;
using System.Linq;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Common;
using Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Input;
using Xunit;
 
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess
{
    /// <summary>
    /// Provides a means of interacting with the Visual Studio editor by remoting calls into Visual Studio.
    /// </summary>
    public partial class Editor_OutOfProc : TextViewWindow_OutOfProc
    {
        public new Verifier Verify { get; }
 
        private readonly Editor_InProc _editorInProc;
        private readonly VisualStudioInstance _instance;
 
        internal Editor_OutOfProc(VisualStudioInstance visualStudioInstance)
            : base(visualStudioInstance)
        {
            _instance = visualStudioInstance;
            _editorInProc = (Editor_InProc)_textViewWindowInProc;
            Verify = new Verifier(this, _instance);
        }
 
        internal override TextViewWindow_InProc CreateInProcComponent(VisualStudioInstance visualStudioInstance)
            => CreateInProcComponent<Editor_InProc>(visualStudioInstance);
 
        public void Activate()
            => _editorInProc.Activate();
 
        public string GetText()
            => _editorInProc.GetText();
 
        public void SetText(string value)
            => _editorInProc.SetText(value);
 
        public string GetCurrentLineText()
            => _editorInProc.GetCurrentLineText();
 
        public string GetLineTextBeforeCaret()
            => _editorInProc.GetLineTextBeforeCaret();
 
        public string GetLineTextAfterCaret()
            => _editorInProc.GetLineTextAfterCaret();
 
        public void MoveCaret(int position)
            => _editorInProc.MoveCaret(position);
 
        public ImmutableArray<TextSpan> GetTagSpans(string tagId)
        {
            if (tagId == InlineRenameDialog_OutOfProc.ValidRenameTag)
            {
                _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.Rename);
            }
 
            var tagInfo = _editorInProc.GetTagSpans(tagId).ToList();
 
            // The spans are returned in an array:
            //    [s1.Start, s1.Length, s2.Start, s2.Length, ...]
            // Reconstruct the spans from their component parts
 
            var builder = ArrayBuilder<TextSpan>.GetInstance();
 
            for (var i = 0; i < tagInfo.Count; i += 2)
            {
                builder.Add(new TextSpan(tagInfo[i], tagInfo[i + 1]));
            }
 
            return builder.ToImmutableAndFree();
        }
 
        public void InvokeNavigateToNextHighlightedReference()
        {
            _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.ReferenceHighlighting);
            _instance.ExecuteCommand(WellKnownCommandNames.Edit_NextHighlightedReference);
        }
 
        public string GetCurrentCompletionItem()
        {
            WaitForCompletionSet();
            return _editorInProc.GetCurrentCompletionItem();
        }
 
        public bool IsCompletionActive()
        {
            WaitForCompletionSet();
            return _editorInProc.IsCompletionActive();
        }
 
        public void InvokeSignatureHelp()
        {
            _instance.ExecuteCommand(WellKnownCommandNames.Edit_ParameterInfo);
            _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp);
        }
 
        public bool IsSignatureHelpActive()
        {
            WaitForSignatureHelp();
            return _editorInProc.IsSignatureHelpActive();
        }
 
        public Signature GetCurrentSignature()
        {
            WaitForSignatureHelp();
            return _editorInProc.GetCurrentSignature();
        }
 
        public void SelectTextInCurrentDocument(string text)
        {
            PlaceCaret(text, charsOffset: -1, occurrence: 0, extendSelection: false, selectBlock: false);
            PlaceCaret(text, charsOffset: 0, occurrence: 0, extendSelection: true, selectBlock: false);
        }
 
        public int GetLine() => _editorInProc.GetLine();
 
        public int GetColumn() => _editorInProc.GetColumn();
 
        public void ReplaceText(string oldText, string newText)
            => _editorInProc.ReplaceText(oldText, newText);
 
        public bool IsCaretOnScreen()
            => _editorInProc.IsCaretOnScreen();
 
        public void AddWinFormButton(string buttonName)
            => _editorInProc.AddWinFormButton(buttonName);
 
        public void DeleteWinFormButton(string buttonName)
            => _editorInProc.DeleteWinFormButton(buttonName);
 
        public void EditWinFormButtonProperty(string buttonName, string propertyName, string propertyValue, string? propertyTypeName = null)
            => _editorInProc.EditWinFormButtonProperty(buttonName, propertyName, propertyValue, propertyTypeName);
 
        public void EditWinFormButtonEvent(string buttonName, string eventName, string eventHandlerName)
            => _editorInProc.EditWinFormButtonEvent(buttonName, eventName, eventHandlerName);
 
        public string? GetWinFormButtonPropertyValue(string buttonName, string propertyName)
            => _editorInProc.GetWinFormButtonPropertyValue(buttonName, propertyName);
 
        /// <summary>
        /// Sends key strokes to the active editor in Visual Studio. Various types are supported by this method:
        /// <see cref="string"/> (each character will be sent separately, <see cref="char"/>, <see cref="VirtualKey"/>
        /// and <see cref="KeyPress"/>.
        /// </summary>
        public void SendKeys(params object[] keys)
        {
            Activate();
            VisualStudioInstance.SendKeys.Send(keys);
        }
 
        public void VerifyDialog(string dialogName, bool isOpen)
            => _editorInProc.VerifyDialog(dialogName, isOpen);
 
        public void PressDialogButton(string dialogAutomationName, string buttonAutomationName)
            => _editorInProc.PressDialogButton(dialogAutomationName, buttonAutomationName);
 
        public void DialogSendKeys(string dialogAutomationName, params object[] keys)
            => _editorInProc.DialogSendKeys(dialogAutomationName, keys);
 
        public void Undo()
            => _editorInProc.Undo();
 
        public void Redo()
            => _editorInProc.Redo();
 
        public ClassifiedToken[] GetLightbulbPreviewClassification(string menuText)
            => _editorInProc.GetLightbulbPreviewClassifications(menuText);
 
        public void SetUseSuggestionMode(bool value)
        {
            Assert.False(IsCompletionActive());
            _editorInProc.SetUseSuggestionMode(value);
        }
 
        public TextSpan[] GetKeywordHighlightTags()
            => Deserialize(_editorInProc.GetHighlightTags());
 
        public TextSpan[] GetOutliningSpans()
        {
            _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.Outlining);
            return Deserialize(_editorInProc.GetOutliningSpans());
        }
 
        private static TextSpan[] Deserialize(string[] v)
        {
            // returned tag looks something like 'text'[12-13]
            return v.Select(tag =>
            {
                var open = tag.LastIndexOf('[') + 1;
                var comma = tag.LastIndexOf('-');
                var close = tag.LastIndexOf(']');
                var start = tag[open..comma];
                var end = tag.Substring(comma + 1, close - comma - 1);
                return TextSpan.FromBounds(int.Parse(start), int.Parse(end));
            }).ToArray();
        }
    }
}