/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System.Runtime.CompilerServices; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; namespace dnSpy.Roslyn.Text { /// /// Extension methods /// static class Extensions { /// /// Converts to a /// /// Snapshot /// public static SourceText AsText(this ITextSnapshot textSnapshot) => snapshotToSourceText.GetValue(textSnapshot, createSourceText); // Pass in UTF8 (or any other valid encoding) so we can compile and get a PDB file static readonly ConditionalWeakTable.CreateValueCallback createSourceText = a => new TextSnapshotSourceText(a, Encoding.UTF8); static readonly ConditionalWeakTable snapshotToSourceText = new ConditionalWeakTable(); /// /// Converts to a /// /// Text buffer /// public static SourceTextContainer AsTextContainer(this ITextBuffer textBuffer) => textBufferToContainer.GetValue(textBuffer, createSourceTextContainer); static readonly ConditionalWeakTable.CreateValueCallback createSourceTextContainer = a => new TextBufferSourceTextContainer(a); static readonly ConditionalWeakTable textBufferToContainer = new ConditionalWeakTable(); /// /// Returns a or null /// /// Text container /// public static ITextBuffer? TryFindEditorTextBuffer(this SourceTextContainer textContainer) => (textContainer as TextBufferSourceTextContainer)?.TextBuffer; /// /// Returns the workspace or null /// /// Text buffer /// public static Workspace TryGetWorkspace(this ITextBuffer buffer) { Workspace.TryGetWorkspace(buffer.AsTextContainer(), out var ws); return ws; } /// /// Gets the snapshot or null /// /// Source text /// public static ITextSnapshot? TryFindEditorSnapshot(this SourceText sourceText) => (sourceText as TextSnapshotSourceText)?.TextSnapshot; /// /// Gets the text image or null /// /// Source text /// internal static ITextImage? TryFindEditorTextImage(this SourceText sourceText) => ((sourceText as TextSnapshotSourceText)?.TextSnapshot as ITextSnapshot2)?.TextImage; internal static TextChangeEventArgs ToTextChangeEventArgs(this TextContentChangedEventArgs e) => new TextChangeEventArgs(e.Before.AsText(), e.After.AsText(), e.Changes.ToTextChangeRange()); /// /// Converts to a /// /// Span /// public static TextSpan ToTextSpan(this Span span) => new TextSpan(span.Start, span.Length); /// /// Converts to a /// /// /// public static Span ToSpan(this TextSpan textSpan) => new Span(textSpan.Start, textSpan.Length); internal static TextChangeRange ToTextChangeRange(this ITextChange textChange) => new TextChangeRange(textChange.OldSpan.ToTextSpan(), textChange.NewLength); internal static TextChangeRange[] ToTextChangeRange(this INormalizedTextChangeCollection changes) { var res = new TextChangeRange[changes.Count]; for (int i = 0; i < res.Length; i++) res[i] = changes[i].ToTextChangeRange(); return res; } /// /// Gets the document or null /// /// Snapshot /// public static Document? GetOpenDocumentInCurrentContextWithChanges(this ITextSnapshot snapshot) => snapshot.AsText().GetOpenDocumentInCurrentContextWithChanges(); /// /// Gets the document or null /// /// Source text /// public static Document? GetOpenDocumentInCurrentContextWithChanges(this SourceText text) { // This internal Roslyn method was copied from roslyn/src/Workspaces/Core/Portable/Workspace/TextExtensions.cs if (Workspace.TryGetWorkspace(text.Container, out var workspace)) { var id = workspace.GetDocumentIdInCurrentContext(text.Container); if (id is null || !workspace.CurrentSolution.ContainsDocument(id)) return null; var sol = workspace.CurrentSolution.WithDocumentText(id, text, PreservationMode.PreserveIdentity); return sol.GetDocument(id); } return null; } } }