|
// 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.Collections.Generic;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
internal partial class SuggestedAction
{
internal class CaretPositionRestorer : IDisposable
{
// Bug 5535: By default the standard editor caret is set to have positive affinity. This
// means that if text is added right at the caret then the caret moves to the right and
// is placed after the added text. However, we don't want that. Instead, we want the
// caret to stay where it started at. So we store the caret position here and
// restore it afterwards.
private readonly EventHandler<CaretPositionChangedEventArgs> _caretPositionChangedHandler;
private readonly IList<Tuple<ITextView, IMappingPoint>> _caretPositions;
private readonly ITextBuffer _subjectBuffer;
private readonly ITextBufferAssociatedViewService _associatedViewService;
private bool _caretChanged;
public CaretPositionRestorer(ITextBuffer subjectBuffer, ITextBufferAssociatedViewService associatedViewService)
{
Contract.ThrowIfNull(associatedViewService);
_subjectBuffer = subjectBuffer;
_caretPositionChangedHandler = (s, e) => _caretChanged = true;
_associatedViewService = associatedViewService;
_caretPositions = GetCaretPositions();
}
private IList<Tuple<ITextView, IMappingPoint>> GetCaretPositions()
{
// Currently, only do this if there's a single view
var views = _associatedViewService.GetAssociatedTextViews(_subjectBuffer);
var result = new List<Tuple<ITextView, IMappingPoint>>();
foreach (var view in views)
{
view.Caret.PositionChanged += _caretPositionChangedHandler;
var point = view.GetCaretPoint(_subjectBuffer);
if (point != null)
{
result.Add(Tuple.Create(view, view.BufferGraph.CreateMappingPoint(point.Value, PointTrackingMode.Negative)));
}
}
return result;
}
private void RestoreCaretPositions()
{
if (_caretChanged)
{
return;
}
foreach (var tuple in _caretPositions)
{
var position = tuple.Item1.GetCaretPoint(_subjectBuffer);
if (position != null)
{
var view = tuple.Item1;
if (!view.IsClosed)
{
view.TryMoveCaretToAndEnsureVisible(position.Value);
}
}
}
}
public void Dispose()
{
RestoreCaretPositions();
foreach (var tuple in _caretPositions)
{
tuple.Item1.Caret.PositionChanged -= _caretPositionChangedHandler;
}
}
}
}
}
|