diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj
index 38c51f78eac8822ecab3a650ddaa157d745a76ed..d88f2716eabef41419abd735fd6d392b855b8482 100644
--- a/src/Features/Core/Portable/Features.csproj
+++ b/src/Features/Core/Portable/Features.csproj
@@ -685,7 +685,9 @@
-
+
+
+
\ No newline at end of file
diff --git a/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.SearchResult.cs b/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.SearchResult.cs
index 5677e7dacda7df189444a4b69f6b9a7a6ca7f8b3..982a706559cc89b67ee294df5b140d706279bffa 100644
--- a/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.SearchResult.cs
+++ b/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.SearchResult.cs
@@ -8,7 +8,7 @@
namespace Microsoft.CodeAnalysis.NavigateTo
{
- internal sealed partial class DefaultNavigateToEngineService
+ internal partial class DefaultNavigateToEngineService
{
private class SearchResult : INavigateToSearchResult
{
diff --git a/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.cs b/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.cs
index 05124883187adf1e1f5a508d2ae3980a3e188360..af1ed0f30e07416a2f8e4caafc3a7f9aaa818eb3 100644
--- a/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.cs
+++ b/src/Features/Core/Portable/NavigateTo/DefaultNavigateToEngineService.cs
@@ -16,7 +16,7 @@
namespace Microsoft.CodeAnalysis.NavigateTo
{
[ExportWorkspaceService(typeof(INavigateToEngineService), layer: ServiceLayer.Default), Shared]
- internal partial class DefaultNavigateToEngineService : INavigateToEngineService
+ internal sealed partial class DefaultNavigateToEngineService : INavigateToEngineService
{
public Task> SearchProjectAsync(
Project project, string searchPattern, CancellationToken cancellationToken)
diff --git a/src/VisualStudio/Core/Next/NavigateTo/VisualStudioNavigateToEngineService.cs b/src/VisualStudio/Core/Next/NavigateTo/VisualStudioNavigateToEngineService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d4cbbd8fdd5bdb09f81d14cccc853362e031d26
--- /dev/null
+++ b/src/VisualStudio/Core/Next/NavigateTo/VisualStudioNavigateToEngineService.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.NavigateTo;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Remote.Arguments;
+using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
+using Microsoft.VisualStudio.LanguageServices.Remote;
+
+namespace Microsoft.VisualStudio.LanguageServices.NavigateTo
+{
+ [ExportWorkspaceService(typeof(INavigateToEngineService)), Shared]
+ internal class VisualStudioNavigateToEngineService : INavigateToEngineService
+ {
+ public async Task> SearchDocumentAsync(
+ Document document, string searchPattern, CancellationToken cancellationToken)
+ {
+ var client = await GetRemoteHostClientAsync(document.Project, cancellationToken).ConfigureAwait(false);
+ if (client == null)
+ {
+ return await DefaultNavigateToEngineService.SearchDocumentInCurrentProcessAsync(
+ document, searchPattern, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ return await SearchDocumentInRemoteProcessAsync(
+ client, document, searchPattern, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task> SearchDocumentInRemoteProcessAsync(
+ RemoteHostClient client, Document document, string searchPattern, CancellationToken cancellationToken)
+ {
+ var solution = document.Project.Solution;
+
+ using (var session = await client.CreateCodeAnalysisServiceSessionAsync(
+ solution, cancellationToken).ConfigureAwait(false))
+ {
+ var serializableResults = await session.InvokeAsync(
+ WellKnownServiceHubServices.CodeAnalysisService_SearchDocumentAsync,
+ SerializableDocumentId.Dehydrate(document),
+ searchPattern).ConfigureAwait(false);
+
+ return serializableResults.Select(r => r.Rehydrate(solution)).ToImmutableArray();
+ }
+ }
+
+ public async Task> SearchProjectAsync(
+ Project project, string searchPattern, CancellationToken cancellationToken)
+ {
+ var client = await GetRemoteHostClientAsync(project, cancellationToken).ConfigureAwait(false);
+ if (client == null)
+ {
+ return await DefaultNavigateToEngineService.SearchProjectInCurrentProcessAsync(
+ project, searchPattern, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ return await SearchProjectInRemoteProcessAsync(
+ client, project, searchPattern, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task> SearchProjectInRemoteProcessAsync(
+ RemoteHostClient client, Project project, string searchPattern, CancellationToken cancellationToken)
+ {
+ var solution = project.Solution;
+
+ using (var session = await client.CreateCodeAnalysisServiceSessionAsync(
+ solution, cancellationToken).ConfigureAwait(false))
+ {
+ var serializableResults = await session.InvokeAsync(
+ WellKnownServiceHubServices.CodeAnalysisService_SearchProjectAsync,
+ SerializableProjectId.Dehydrate(project.Id),
+ searchPattern).ConfigureAwait(false);
+
+ return serializableResults.Select(r => r.Rehydrate(solution)).ToImmutableArray();
+ }
+ }
+
+ private static Task GetRemoteHostClientAsync(
+ Project project, CancellationToken cancellationToken)
+ {
+ var clientService = project.Solution.Workspace.Services.GetService();
+ return clientService.GetRemoteHostClientAsync(cancellationToken);
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj b/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
index 923b81c8a530f65bac281620c82782622e6d45e4..57fe37eea6efa050a1338dddf39581cc668def1d 100644
--- a/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
+++ b/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
@@ -89,6 +89,9 @@
Shared\Extensions.cs
+
+ Shared\RemoteArguments.cs
+
Shared\ServerDirectStream.cs
@@ -110,6 +113,7 @@
+
@@ -133,5 +137,6 @@
+
\ No newline at end of file
diff --git a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
index 209b2209d3b0a57c323f0a8df268a03e2364f5c2..c3bc711045d78b5f4c731e1a90e79c18fb48fddc 100644
--- a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
+++ b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
@@ -19,6 +19,10 @@
{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}
CodeAnalysis
+
+ {3cdeeab7-2256-418a-beb2-620b5cb16302}
+ EditorFeatures
+
{edc68a0e-c68d-4a74-91b7-bf38ec909888}
Features
@@ -50,6 +54,7 @@
+
@@ -74,6 +79,7 @@
+
diff --git a/src/Workspaces/Remote/ServiceHub/Shared/RemoteArguments.cs b/src/Workspaces/Remote/ServiceHub/Shared/RemoteArguments.cs
new file mode 100644
index 0000000000000000000000000000000000000000..439b74c406c84acf38d44b6e113adeb189c8ce15
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Shared/RemoteArguments.cs
@@ -0,0 +1,200 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis.Editor.Implementation.NavigateTo;
+using Microsoft.CodeAnalysis.NavigateTo;
+using Microsoft.CodeAnalysis.Navigation;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.Remote.Arguments
+{
+ #region Common Arguments
+
+ ///
+ /// Arguments to pass from client to server when performing operations
+ ///
+ internal class SerializableProjectId
+ {
+ public Guid Id;
+ public string DebugName;
+
+ public static SerializableProjectId Dehydrate(ProjectId id)
+ {
+ return new SerializableProjectId { Id = id.Id, DebugName = id.DebugName };
+ }
+
+ public ProjectId Rehydrate()
+ {
+ return ProjectId.CreateFromSerialized(Id, DebugName);
+ }
+ }
+
+ internal class SerializableDocumentId
+ {
+ public SerializableProjectId ProjectId;
+ public Guid Id;
+ public string DebugName;
+
+ public static SerializableDocumentId Dehydrate(Document document)
+ {
+ return Dehydrate(document.Id);
+ }
+
+ public static SerializableDocumentId Dehydrate(DocumentId id)
+ {
+ return new SerializableDocumentId
+ {
+ ProjectId = SerializableProjectId.Dehydrate(id.ProjectId),
+ Id = id.Id,
+ DebugName = id.DebugName
+ };
+ }
+
+ public DocumentId Rehydrate()
+ {
+ return DocumentId.CreateFromSerialized(
+ ProjectId.Rehydrate(), Id, DebugName);
+ }
+ }
+
+ internal class SerializableTextSpan
+ {
+ public int Start;
+ public int Length;
+
+ public static SerializableTextSpan Dehydrate(TextSpan textSpan)
+ {
+ return new SerializableTextSpan { Start = textSpan.Start, Length = textSpan.Length };
+ }
+
+ public TextSpan Rehydrate()
+ {
+ return new TextSpan(Start, Length);
+ }
+ }
+
+ internal class SerializableTaggedText
+ {
+ public string Tag;
+ public string Text;
+
+ public static SerializableTaggedText Dehydrate(TaggedText taggedText)
+ {
+ return new SerializableTaggedText { Tag = taggedText.Tag, Text = taggedText.Text };
+ }
+
+ public TaggedText Rehydrate()
+ {
+ return new TaggedText(Tag, Text);
+ }
+ }
+
+ #endregion
+
+ #region NavigateTo
+
+ internal class SerializableNavigateToSearchResult
+ {
+ public string AdditionalInformation;
+
+ public string Kind;
+ public NavigateToMatchKind MatchKind;
+ public bool IsCaseSensitive;
+ public string Name;
+ public string SecondarySort;
+ public string Summary;
+
+ public SerializableNavigableItem NavigableItem;
+
+ internal INavigateToSearchResult Rehydrate(Solution solution)
+ {
+ return new NavigateToSearchResult(
+ AdditionalInformation, Kind, MatchKind, IsCaseSensitive,
+ Name, SecondarySort, Summary, NavigableItem.Rehydrate(solution));
+ }
+
+ private class NavigateToSearchResult : INavigateToSearchResult
+ {
+ public string AdditionalInformation { get; }
+ public string Kind { get; }
+ public NavigateToMatchKind MatchKind { get; }
+ public bool IsCaseSensitive { get; }
+ public string Name { get; }
+ public string SecondarySort { get; }
+ public string Summary { get; }
+
+ public INavigableItem NavigableItem { get; }
+
+ public NavigateToSearchResult(string additionalInformation, string kind, NavigateToMatchKind matchKind, bool isCaseSensitive, string name, string secondarySort, string summary, INavigableItem navigableItem)
+ {
+ AdditionalInformation = additionalInformation;
+ Kind = kind;
+ MatchKind = matchKind;
+ IsCaseSensitive = isCaseSensitive;
+ Name = name;
+ SecondarySort = secondarySort;
+ Summary = summary;
+ NavigableItem = navigableItem;
+ }
+ }
+ }
+
+ internal class SerializableNavigableItem
+ {
+ public Glyph Glyph;
+
+ public SerializableTaggedText[] DisplayTaggedParts;
+
+ public bool DisplayFileLocation;
+
+ public bool IsImplicitlyDeclared;
+
+ public SerializableDocumentId Document;
+ public SerializableTextSpan SourceSpan;
+
+ SerializableNavigableItem[] ChildItems;
+
+ public INavigableItem Rehydrate(Solution solution)
+ {
+ var childItems = ChildItems == null
+ ? ImmutableArray.Empty
+ : ChildItems.Select(c => c.Rehydrate(solution)).ToImmutableArray();
+ return new NavigableItem(
+ Glyph, DisplayTaggedParts.Select(p => p.Rehydrate()).ToImmutableArray(),
+ DisplayFileLocation, IsImplicitlyDeclared,
+ solution.GetDocument(Document.Rehydrate()),
+ SourceSpan.Rehydrate(),
+ childItems);
+ }
+
+ private class NavigableItem : INavigableItem
+ {
+ public Glyph Glyph { get; }
+ public ImmutableArray DisplayTaggedParts { get; }
+ public bool DisplayFileLocation { get; }
+ public bool IsImplicitlyDeclared { get; }
+
+ public Document Document { get; }
+ public TextSpan SourceSpan { get; }
+
+ public ImmutableArray ChildItems { get; }
+
+ public NavigableItem(
+ Glyph glyph, ImmutableArray displayTaggedParts,
+ bool displayFileLocation, bool isImplicitlyDeclared, Document document, TextSpan sourceSpan, ImmutableArray childItems)
+ {
+ Glyph = glyph;
+ DisplayTaggedParts = displayTaggedParts;
+ DisplayFileLocation = displayFileLocation;
+ IsImplicitlyDeclared = isImplicitlyDeclared;
+ Document = document;
+ SourceSpan = sourceSpan;
+ ChildItems = childItems;
+ }
+ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/Workspaces/Remote/ServiceHub/Shared/WellKnownServiceHubServices.cs b/src/Workspaces/Remote/ServiceHub/Shared/WellKnownServiceHubServices.cs
index 8ccd643640cd3a0377046a0b8685abce07a6e389..c7db34f37be4a91132e4905a9a57e934e72a0cc1 100644
--- a/src/Workspaces/Remote/ServiceHub/Shared/WellKnownServiceHubServices.cs
+++ b/src/Workspaces/Remote/ServiceHub/Shared/WellKnownServiceHubServices.cs
@@ -14,6 +14,10 @@ internal static class WellKnownServiceHubServices
public const string CodeAnalysisService_FindReferenceMethodsAsync = "FindReferenceMethodsAsync";
public const string CodeAnalysisService_GetFullyQualifiedName = "GetFullyQualifiedName";
+ // NavigateTo
+ public const string CodeAnalysisService_SearchDocumentAsync = "SearchDocumentAsync";
+ public const string CodeAnalysisService_SearchProjectAsync = "SearchProjectAsync";
+
public const string AssetService_RequestAssetAsync = "RequestAssetAsync";
}
}