Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TextEdits support to InlayHints #2385

Merged
merged 10 commits into from
Apr 18, 2022
2 changes: 1 addition & 1 deletion build/Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<MicrosoftTestPackageVersion>17.0.0</MicrosoftTestPackageVersion>
<MSBuildPackageVersion>17.0.0</MSBuildPackageVersion>
<NuGetPackageVersion>6.2.0-preview.2.80</NuGetPackageVersion>
<RoslynPackageVersion>4.2.0-3.22169.1</RoslynPackageVersion>
<RoslynPackageVersion>4.3.0-1.22215.1</RoslynPackageVersion>
<XunitPackageVersion>2.4.1</XunitPackageVersion>
</PropertyGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/OmniSharp.Abstractions/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ internal static class Configuration
{
public static bool ZeroBasedIndices = false;

public const string RoslynVersion = "4.2.0.0";
public const string RoslynVersion = "4.3.0.0";
public const string RoslynPublicKeyToken = "31bf3856ad364e35";

public readonly static string RoslynFeatures = GetRoslynAssemblyFullName("Microsoft.CodeAnalysis.Features");
Expand Down
64 changes: 61 additions & 3 deletions src/OmniSharp.Abstractions/Models/v1/InlayHints/InlayHint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,88 @@ namespace OmniSharp.Models.v1.InlayHints;

public sealed record InlayHint
{
/// <summary>
/// The position of this hint.
/// </summary>
public Point Position { get; set; }

/// <summary>
/// The label of this hint. A human readable string.
/// </summary>
public string Label { get; set; }

/// <summary>
/// The tooltip text when you hover over this item.
/// </summary>
public string? Tooltip { get; set; }

/// <summary>
/// Optional text edits that are performed when accepting this inlay hint.
/// </summary>
public LinePositionSpanTextChange[]? TextEdits { get; set; }

/// <summary>
/// A data entry field that is preserved on a inlay hint between a <see cref="InlayHintRequest" /> and a <see cref="InlayHintResolveRequest" />.
/// </summary>
public (string SolutionVersion, int Position) Data { get; set; }

#nullable enable
public override string ToString()
{
return $"InlineHint {{ {nameof(Position)} = {Position}, {nameof(Label)} = {Label}, {nameof(Tooltip)} = {Tooltip} }}";
var textEdits = TextEdits is null ? "null" : $"[ {string.Join<LinePositionSpanTextChange>(", ", TextEdits)} ]";
return $"InlayHint {{ {nameof(Position)} = {Position}, {nameof(Label)} = {Label}, {nameof(Tooltip)} = {Tooltip ?? "null"}, {nameof(TextEdits)} = {textEdits} }}";
}

public bool Equals(InlayHint? other)
{
if (ReferenceEquals(this, other)) return true;
if (other is null) return false;

return Position == other.Position && Label == other.Label && Tooltip == other.Tooltip;
return Position == other.Position
&& Label == other.Label
&& Tooltip == other.Tooltip
&& TextEditsEqual(TextEdits, other.TextEdits);
}

private static bool TextEditsEqual(LinePositionSpanTextChange[]? a, LinePositionSpanTextChange[]? b)
{
if (a is null)
{
return b is null;
}

if (b is null)
{
return false;
}

if (a.Length != b.Length)
{
return false;
}

for (int index = 0; index < a.Length; index++)
{
if (!a[index].Equals(b[index]))
{
return false;
}
}

return true;
}

public override int GetHashCode() => (Position, Label, Tooltip).GetHashCode();
public override int GetHashCode() => (Position, Label, Tooltip, TextEdits?.GetHashCode() ?? 0).GetHashCode();
}

public enum InlayHintKind
{
/// <summary>
/// An inlay hint that for a type annotation.
JoeRobich marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
Type = 1,
/// <summary>
/// An inlay hint that is for a parameter.
/// </summary>
Parameter = 2,
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public override string ToString()
{
var displayText = NewText != null
? NewText.Replace("\r", @"\r").Replace("\n", @"\n").Replace("\t", @"\t")
: string.Empty;
: "null";

return $"StartLine={StartLine}, StartColumn={StartColumn}, EndLine={EndLine}, EndColumn={EndColumn}, NewText='{displayText}'";
return $"LinePositionSpanTextChange {{ StartLine={StartLine}, StartColumn={StartColumn}, EndLine={EndLine}, EndColumn={EndColumn}, NewText={displayText} }}";
}
}
}
10 changes: 5 additions & 5 deletions src/OmniSharp.Http.Driver/app.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Features" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp.Features" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Dataflow" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
Expand Down
10 changes: 5 additions & 5 deletions src/OmniSharp.LanguageServerProtocol/app.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Features" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp.Features" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Dataflow" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -12,6 +13,7 @@
using Microsoft.Extensions.Options;
using OmniSharp.Extensions;
using OmniSharp.Mef;
using OmniSharp.Models;
using OmniSharp.Models.v1.InlayHints;
using OmniSharp.Options;
using OmniSharp.Roslyn.CSharp.Helpers;
Expand Down Expand Up @@ -139,6 +141,7 @@ public List<InlayHint> MapAndCacheHints(ImmutableArray<OmniSharpInlineHint> rosl
{
Label = string.Concat(hint.DisplayParts),
Position = text.GetPointFromPosition(hint.Span.End),
TextEdits = ConvertToTextChanges(hint.ReplacementTextChange, text),
Data = (solutionVersionString, position)
});

Expand All @@ -152,6 +155,27 @@ public List<InlayHint> MapAndCacheHints(ImmutableArray<OmniSharpInlineHint> rosl
return resultList;
}

internal static LinePositionSpanTextChange[]? ConvertToTextChanges(TextChange? textChange, SourceText sourceText)
{
if (textChange.HasValue == false)
{
return Array.Empty<LinePositionSpanTextChange>();
}

var changeLinePositionSpan = sourceText.Lines.GetLinePositionSpan(textChange.Value.Span);
return new[]
{
new LinePositionSpanTextChange()
JoeRobich marked this conversation as resolved.
Show resolved Hide resolved
{
NewText = textChange.Value.NewText ?? "",
StartLine = changeLinePositionSpan.Start.Line,
StartColumn = changeLinePositionSpan.Start.Character,
EndLine = changeLinePositionSpan.End.Line,
EndColumn = changeLinePositionSpan.End.Character
}
};
}

public bool TryGetFromCache(InlayHint hint, out OmniSharpInlineHint roslynHint, [NotNullWhen(true)] out Document? document)
{
(roslynHint, document) = (default, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.MetadataAsSource;
using OmniSharp.Extensions;
using OmniSharp.Options;
using OmniSharp.Roslyn.CSharp.Workers.Formatting;

namespace OmniSharp.Roslyn
{
Expand All @@ -13,9 +15,12 @@ public class MetadataExternalSourceService : BaseExternalSourceService, IExterna
{
private const string MetadataKey = "$Metadata$";

private readonly OmniSharpOptions _omnisharpOptions;

[ImportingConstructor]
public MetadataExternalSourceService() : base()
public MetadataExternalSourceService(OmniSharpOptions omnisharpOptions) : base()
{
_omnisharpOptions = omnisharpOptions;
}

public async Task<(Document document, string documentPath)> GetAndAddExternalSymbolDocument(Project project, ISymbol symbol, CancellationToken cancellationToken)
Expand Down Expand Up @@ -47,11 +52,13 @@ public async Task<(Document document, string documentPath)> GetAndAddExternalSym
var topLevelSymbol = symbol.GetTopLevelContainingNamedType();

var temporaryDocument = metadataProject.AddDocument(fileName, string.Empty);
var formattingOptions = await FormattingWorker.GetFormattingOptionsAsync(temporaryDocument, _omnisharpOptions);

document = await OmniSharpMetadataAsSourceService.AddSourceToAsync(
temporaryDocument,
await metadataProject.GetCompilationAsync(),
topLevelSymbol,
formattingOptions,
cancellationToken);

_cache.TryAdd(fileName, document);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,16 @@ private async Task<Document> FixSpecificDiagnosticIdAsync(Document document, str
};

var fixAllContext = OmniSharpCodeFixContextFactory.CreateFixAllContext(
document, document.Project, codeFixProvider, roslynScope, action.EquivalenceKey, ImmutableArray.Create(diagnosticId), _fixAllDiagnosticProvider,
_ => codeActionOptions, cancellationToken);
document,
primaryDiagnostic.Location.SourceSpan,
document.Project,
codeFixProvider,
roslynScope,
action.EquivalenceKey,
ImmutableArray.Create(diagnosticId),
_fixAllDiagnosticProvider,
_ => codeActionOptions,
cancellationToken);

_logger.LogTrace("Finding FixAll fix for {0}.", diagnosticId);
var fixes = await fixAllProvider.GetFixAsync(fixAllContext);
Expand Down
10 changes: 5 additions & 5 deletions src/OmniSharp.Stdio.Driver/app.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Features" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp.Features" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Dataflow" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
Expand Down
12 changes: 6 additions & 6 deletions tests/OmniSharp.Cake.Tests/CompletionFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace OmniSharp.Cake.Tests
{
public class CompletionFacts : CakeSingleRequestHandlerTestFixture<CompletionHandler>
{
private const int ImportCompletionTimeout = 1000;
private const int ImportCompletionTimeout = 2000;
private readonly ILogger _logger;

public CompletionFacts(ITestOutputHelper testOutput) : base(testOutput)
Expand All @@ -30,7 +30,7 @@ public async Task ShouldGetCompletionFromHostObject()
{
const string input = @"TaskSe$$";

using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy : false))
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy: false))
using (var host = CreateOmniSharpHost(testProject.Directory))
{
var fileName = Path.Combine(testProject.Directory, "build.cake");
Expand All @@ -50,7 +50,7 @@ public async Task ShouldGetCompletionFromDSL()
Inform$$
});";

using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy : false))
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy: false))
using (var host = CreateOmniSharpHost(testProject.Directory))
{
var fileName = Path.Combine(testProject.Directory, "build.cake");
Expand All @@ -70,7 +70,7 @@ public async Task ShouldResolveFromDSL()
Inform$$
});";

using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy : false))
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy: false))
using (var host = CreateOmniSharpHost(testProject.Directory))
{
var fileName = Path.Combine(testProject.Directory, "build.cake");
Expand All @@ -90,7 +90,7 @@ public async Task ShouldRemoveAdditionalTextEditsFromResolvedCompletions()
{
const string input = @"var regex = new Rege$$";

using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy : false))
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy: false))
using (var host = CreateOmniSharpHost(testProject.Directory,
new[] { new KeyValuePair<string, string>("RoslynExtensionsOptions:EnableImportCompletion", "true") }))
{
Expand Down Expand Up @@ -141,7 +141,7 @@ class FooChild : Foo
}
";

using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy : false))
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy: false))
using (var host = CreateOmniSharpHost(testProject.Directory))
{
var fileName = Path.Combine(testProject.Directory, "build.cake");
Expand Down
2 changes: 1 addition & 1 deletion tests/OmniSharp.Roslyn.CSharp.Tests/CompletionFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace OmniSharp.Roslyn.CSharp.Tests
{
public class CompletionFacts : AbstractTestFixture
{
private const int ImportCompletionTimeout = 1000;
private const int ImportCompletionTimeout = 2000;
private readonly ILogger _logger;

private string EndpointName => OmniSharpEndpoints.Completion;
Expand Down
Loading