File: DebuggerIntelliSense\DebuggerTextView.cs
Web Access
Project: src\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_pxr0p0dn_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// 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.Windows;
using System.Windows.Media;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense;
 
internal partial class DebuggerTextView : IWpfTextView, IDebuggerTextView2, ITextView2
{
    /// <summary>
    /// The actual debugger view of the watch or immediate window that we're wrapping
    /// </summary>
    private readonly IWpfTextView _innerTextView;
    private readonly IVsTextLines _debuggerTextLinesOpt;
 
    private IMultiSelectionBroker _multiSelectionBroker;
 
    // This name "CompletionRoot" is specified on the Editor side.
    // Roslyn must match the name.
    // The const should be removed with resolution of https://github.com/dotnet/roslyn/issues/31189
    public const string CompletionRoot = nameof(CompletionRoot);
 
    public DebuggerTextView(
        IWpfTextView innerTextView,
        IBufferGraph bufferGraph,
        IVsTextLines debuggerTextLinesOpt,
        bool isImmediateWindow)
    {
        _innerTextView = innerTextView;
        _debuggerTextLinesOpt = debuggerTextLinesOpt;
        BufferGraph = bufferGraph;
        IsImmediateWindow = isImmediateWindow;
 
        // The editor requires the current top buffer.
        // TODO it seems to be a hack. It should be removed.
        // Here is an issue to track: https://github.com/dotnet/roslyn/issues/31189
        // Starting debugging for the second time, we already have the property set.
        _innerTextView.Properties[CompletionRoot] = bufferGraph.TopBuffer;
    }
 
    /// <summary>
    /// We basically replace the innerTextView's BufferGraph with our own custom projection graph
    /// that projects the immediate window contents into a context buffer:
    /// 
    ///             (1)
    ///         (2)     (5)
    ///         (3)     (6)
    ///         (4)
    /// (1) Top level projection buffer - the subject buffer used by intellisense
    /// (2/3) Currently a double projection buffer combo that elides away the ? in the immediate window, and may add some 
    ///       boilerplate code to force an expression context.
    /// (4) innerTextView.TextBuffer, what the user actually sees in the watch/immediate windows
    /// (5) A read-only projection of (6)
    /// (6) The context buffer which is typically a source file
    /// 
    /// </summary>
    public IBufferGraph BufferGraph
    {
        get;
    }
 
    public bool IsImmediateWindow
    {
        get;
    }
 
    public uint StartBufferUpdate()
    {
        // null in unit tests
        if (_debuggerTextLinesOpt == null)
        {
            return 0;
        }
 
        _debuggerTextLinesOpt.GetStateFlags(out var bufferFlags);
        _debuggerTextLinesOpt.SetStateFlags((uint)((BUFFERSTATEFLAGS)bufferFlags & ~BUFFERSTATEFLAGS.BSF_USER_READONLY));
        return bufferFlags;
    }
 
    public void EndBufferUpdate(uint cookie)
    {
        // null in unit tests
        _debuggerTextLinesOpt?.SetStateFlags(cookie);
    }
 
    public ITextCaret Caret
    {
        get { return _innerTextView.Caret; }
    }
 
    public bool HasAggregateFocus
    {
        get { return _innerTextView.HasAggregateFocus; }
    }
 
    public bool InLayout
    {
        get { return _innerTextView.InLayout; }
    }
 
    public bool IsClosed
    {
        get { return _innerTextView.IsClosed; }
    }
 
    public bool IsMouseOverViewOrAdornments
    {
        get { return _innerTextView.IsMouseOverViewOrAdornments; }
    }
 
    public double LineHeight
    {
        get { return _innerTextView.LineHeight; }
    }
 
    public double MaxTextRightCoordinate
    {
        get { return _innerTextView.MaxTextRightCoordinate; }
    }
 
    public IEditorOptions Options
    {
        get { return _innerTextView.Options; }
    }
 
    public PropertyCollection Properties
    {
        get { return _innerTextView.Properties; }
    }
 
    public ITrackingSpan ProvisionalTextHighlight
    {
        get
        {
            return _innerTextView.ProvisionalTextHighlight;
        }
 
        set
        {
            _innerTextView.ProvisionalTextHighlight = value;
        }
    }
 
    public ITextViewRoleSet Roles
    {
        get { return _innerTextView.Roles; }
    }
 
    public ITextSelection Selection
    {
        get { return _innerTextView.Selection; }
    }
 
    public ITextViewLineCollection TextViewLines
    {
        get { return _innerTextView.TextViewLines; }
    }
 
    public ITextViewModel TextViewModel
    {
        get { return _innerTextView.TextViewModel; }
    }
 
    public IViewScroller ViewScroller
    {
        get { return _innerTextView.ViewScroller; }
    }
 
    public double ViewportBottom
    {
        get { return _innerTextView.ViewportBottom; }
    }
 
    public double ViewportHeight
    {
        get { return _innerTextView.ViewportHeight; }
    }
 
    public double ViewportLeft
    {
        get
        {
            return _innerTextView.ViewportLeft;
        }
 
        set
        {
            _innerTextView.ViewportLeft = value;
        }
    }
 
    public double ViewportRight
    {
        get { return _innerTextView.ViewportRight; }
    }
 
    public double ViewportTop
    {
        get { return _innerTextView.ViewportTop; }
    }
 
    public double ViewportWidth
    {
        get { return _innerTextView.ViewportWidth; }
    }
 
    public ITextSnapshot VisualSnapshot
    {
        get { return _innerTextView.VisualSnapshot; }
    }
 
    public ITextDataModel TextDataModel
    {
        get { return _innerTextView.TextDataModel; }
    }
 
    public ITextBuffer TextBuffer
    {
        get
        {
            return _innerTextView.TextBuffer;
        }
    }
 
    public ITextSnapshot TextSnapshot
    {
        get
        {
            return _innerTextView.TextSnapshot;
        }
    }
 
    public FrameworkElement VisualElement
    {
        get
        {
            return _innerTextView.VisualElement;
        }
    }
 
    public Brush Background
    {
        get
        {
            return _innerTextView.Background;
        }
 
        set
        {
            _innerTextView.Background = value;
        }
    }
 
    IWpfTextViewLineCollection IWpfTextView.TextViewLines
    {
        get
        {
            return _innerTextView.TextViewLines;
        }
    }
 
    public IFormattedLineSource FormattedLineSource
    {
        get
        {
            return _innerTextView.FormattedLineSource;
        }
    }
 
    public ILineTransformSource LineTransformSource
    {
        get
        {
            return _innerTextView.LineTransformSource;
        }
    }
 
    public double ZoomLevel
    {
        get
        {
            return _innerTextView.ZoomLevel;
        }
 
        set
        {
            _innerTextView.ZoomLevel = value;
        }
    }
 
    public bool InOuterLayout => throw new NotImplementedException();
 
    public IMultiSelectionBroker MultiSelectionBroker
    {
        get
        {
            _multiSelectionBroker ??= _innerTextView.GetMultiSelectionBroker();
 
            return _multiSelectionBroker;
        }
    }
 
    public void Close()
        => throw new NotSupportedException();
 
    public void DisplayTextLineContainingBufferPosition(SnapshotPoint bufferPosition, double verticalDistance, ViewRelativePosition relativeTo, double? viewportWidthOverride, double? viewportHeightOverride)
        => throw new NotSupportedException();
 
    public void DisplayTextLineContainingBufferPosition(SnapshotPoint bufferPosition, double verticalDistance, ViewRelativePosition relativeTo)
        => throw new NotSupportedException();
 
    public SnapshotSpan GetTextElementSpan(SnapshotPoint point)
        => throw new NotSupportedException();
 
    public ITextViewLine GetTextViewLineContainingBufferPosition(SnapshotPoint bufferPosition)
        => _innerTextView.GetTextViewLineContainingBufferPosition(bufferPosition);
 
    public void QueueSpaceReservationStackRefresh()
        => throw new NotSupportedException();
 
    public IAdornmentLayer GetAdornmentLayer(string name)
        => _innerTextView.GetAdornmentLayer(name);
 
    public ISpaceReservationManager GetSpaceReservationManager(string name)
        => _innerTextView.GetSpaceReservationManager(name);
 
    IWpfTextViewLine IWpfTextView.GetTextViewLineContainingBufferPosition(SnapshotPoint bufferPosition)
        => _innerTextView.GetTextViewLineContainingBufferPosition(bufferPosition);
 
    public void Cleanup()
    {
        // The innerTextView of the immediate window never closes, but we want
        // our completion subscribers to unsubscribe from events when this
        // DebuggerTextView is no longer in use.
        if (this.IsImmediateWindow)
        {
            this.ClosedInternal?.Invoke(this, EventArgs.Empty);
        }
 
        _innerTextView.Properties.RemoveProperty(CompletionRoot);
    }
 
    public void QueuePostLayoutAction(Action action) => _innerTextView.QueuePostLayoutAction(action);
 
    public bool TryGetTextViewLines(out ITextViewLineCollection textViewLines) => _innerTextView.TryGetTextViewLines(out textViewLines);
 
    public bool TryGetTextViewLineContainingBufferPosition(SnapshotPoint bufferPosition, out ITextViewLine textViewLine)
        => _innerTextView.TryGetTextViewLineContainingBufferPosition(bufferPosition, out textViewLine);
 
    private event EventHandler ClosedInternal;
 
#pragma warning disable 67
    public event EventHandler MaxTextRightCoordinateChanged;
#pragma warning restore 67
 
    public event EventHandler Closed
    {
        add
        {
            if (this.IsImmediateWindow)
            {
                this.ClosedInternal += value;
            }
            else
            {
                _innerTextView.Closed += value;
            }
        }
 
        remove
        {
            if (this.IsImmediateWindow)
            {
                this.ClosedInternal -= value;
            }
            else
            {
                _innerTextView.Closed -= value;
            }
        }
    }
 
    public event EventHandler GotAggregateFocus
    {
        add { _innerTextView.GotAggregateFocus += value; }
        remove { _innerTextView.GotAggregateFocus -= value; }
    }
 
    public event EventHandler<TextViewLayoutChangedEventArgs> LayoutChanged
    {
        add { _innerTextView.LayoutChanged += value; }
        remove { _innerTextView.LayoutChanged -= value; }
    }
 
    public event EventHandler LostAggregateFocus
    {
        add { _innerTextView.LostAggregateFocus += value; }
        remove { _innerTextView.LostAggregateFocus -= value; }
    }
 
    public event EventHandler<MouseHoverEventArgs> MouseHover
    {
        add { _innerTextView.MouseHover += value; }
        remove { _innerTextView.MouseHover -= value; }
    }
 
    public event EventHandler ViewportHeightChanged
    {
        add { _innerTextView.ViewportHeightChanged += value; }
        remove { _innerTextView.ViewportHeightChanged -= value; }
    }
 
    public event EventHandler ViewportLeftChanged
    {
        add { _innerTextView.ViewportLeftChanged += value; }
        remove { _innerTextView.ViewportLeftChanged -= value; }
    }
 
    public event EventHandler ViewportWidthChanged
    {
        add { _innerTextView.ViewportWidthChanged += value; }
        remove { _innerTextView.ViewportWidthChanged -= value; }
    }
 
    public event EventHandler<BackgroundBrushChangedEventArgs> BackgroundBrushChanged
    {
        add { _innerTextView.BackgroundBrushChanged += value; }
        remove { _innerTextView.BackgroundBrushChanged -= value; }
    }
 
    public event EventHandler<ZoomLevelChangedEventArgs> ZoomLevelChanged
    {
        add { _innerTextView.ZoomLevelChanged += value; }
        remove { _innerTextView.ZoomLevelChanged -= value; }
    }
}