|
// 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.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview;
internal sealed partial class PreviewUpdater
{
private PreviewDialogWorkspace? _previewWorkspace;
private readonly ITextView _textView;
private DocumentId? _currentDocumentId;
private readonly PreviewTagger _tagger;
public PreviewUpdater(ITextView textView)
{
_textView = textView;
_tagger = new PreviewTagger(textView.TextBuffer);
_textView.Properties[typeof(PreviewTagger)] = _tagger;
}
public void CloseWorkspace()
{
_previewWorkspace?.Dispose();
}
public void UpdateView(TextDocument document, SpanChange spanSource)
{
UpdateBuffer(document);
// Picking a different span: no text change; update span anyway.
_tagger.Span = spanSource.GetSpan();
var spanInBuffer = new SnapshotSpan(_textView.TextBuffer.CurrentSnapshot, new Span(_tagger.Span.Start, 0));
_textView.ViewScroller.EnsureSpanVisible(spanInBuffer, EnsureSpanVisibleOptions.None);
}
private void UpdateBuffer(TextDocument document)
{
// Note, even if the passed TextDocument has the same ID as _currentDocumentId, we still need
// to refresh the buffer; if the user has a set of edits for a single document from a fix all operation,
// you can check and uncheck the individual edits and we show the result. In that case, we're getting new
// snapshots each time of the same document.
if (document.Id == _currentDocumentId)
{
Contract.ThrowIfNull(_previewWorkspace, "We shouldn't have a current document if we don't have a workspace.");
var existingDocument = _previewWorkspace.CurrentSolution.GetRequiredTextDocument(_currentDocumentId);
if (existingDocument.GetTextSynchronously(CancellationToken.None).ContentEquals(document.GetTextSynchronously(CancellationToken.None)))
{
// The contents of the buffer matches what we'd update it to, so no reason to change.
return;
}
}
if (_currentDocumentId != null)
{
Contract.ThrowIfNull(_previewWorkspace, "We shouldn't have a current document if we don't have a workspace.");
var currentDocument = _previewWorkspace.CurrentSolution.GetRequiredTextDocument(_currentDocumentId);
var currentDocumentText = currentDocument.GetTextSynchronously(CancellationToken.None);
_previewWorkspace.CloseDocument(currentDocument, currentDocumentText);
}
_previewWorkspace ??= new PreviewDialogWorkspace(document.Project.Solution);
_currentDocumentId = document.Id;
ApplyDocumentToBuffer(document, out var container);
_previewWorkspace.OpenDocument(document.Id, container);
}
private void ApplyDocumentToBuffer(TextDocument document, out SourceTextContainer container)
{
var contentTypeService = document.Project.Services.GetRequiredService<IContentTypeLanguageService>();
var contentType = contentTypeService.GetDefaultContentType();
_textView.TextBuffer.ChangeContentType(contentType, null);
var documentText = document.GetTextSynchronously(CancellationToken.None).ToString();
using (var edit = _textView.TextBuffer.CreateEdit())
{
edit.Replace(new Span(0, _textView.TextBuffer.CurrentSnapshot.Length), documentText);
edit.ApplyAndLogExceptions();
}
container = _textView.TextBuffer.AsTextContainer();
}
}
|