提交 62d25585 编写于 作者: C Cyrus Najmabadi

Prioritize NavigateTo searches to care most about the current active doc/project.

上级 fcf5fd8a
......@@ -68,11 +68,33 @@ internal async void Search()
{
_progress.AddItems(_solution.Projects.Count());
// Search each project with an independent threadpool task.
var searchTasks = _solution.Projects.Select(
p => Task.Run(() => SearchAsync(p), _cancellationToken)).ToArray();
var workspace = _solution.Workspace;
var docTrackingService = workspace.Services.GetService<IDocumentTrackingService>();
var activeDocIdOpt = docTrackingService?.GetActiveDocument();
var activeDocumentOpt = _solution.GetDocument(activeDocIdOpt);
await Task.WhenAll(searchTasks).ConfigureAwait(false);
if (activeDocumentOpt != null)
{
var activeProject = activeDocumentOpt.Project;
// Search the current project first. That way we can deliver
// results that are closer in scope to the user quicker without
// forcing them to do something like NavToInCurrentDoc
await Task.Run(() => SearchAsync(activeProject, activeDocumentOpt), _cancellationToken).ConfigureAwait(false);
var searchTasks = _solution.Projects
.Where(p => p != activeProject)
.Select(p => Task.Run(() => SearchAsync(p, activeDocumentOpt: null), _cancellationToken)).ToArray();
await Task.WhenAll(searchTasks).ConfigureAwait(false);
}
else
{
// Search each project with an independent threadpool task.
var searchTasks = _solution.Projects.Select(
p => Task.Run(() => SearchAsync(p, activeDocumentOpt: null), _cancellationToken)).ToArray();
await Task.WhenAll(searchTasks).ConfigureAwait(false);
}
}
}
catch (OperationCanceledException)
......@@ -84,11 +106,11 @@ internal async void Search()
}
}
private async Task SearchAsync(Project project)
private async Task SearchAsync(Project project, Document activeDocumentOpt)
{
try
{
await SearchAsyncWorker(project).ConfigureAwait(false);
await SearchAsyncWorker(project, activeDocumentOpt).ConfigureAwait(false);
}
finally
{
......@@ -96,7 +118,7 @@ private async Task SearchAsync(Project project)
}
}
private async Task SearchAsyncWorker(Project project)
private async Task SearchAsyncWorker(Project project, Document activeDocumentOpt)
{
if (_searchCurrentDocument && _currentDocument?.Project != project)
{
......@@ -113,7 +135,7 @@ private async Task SearchAsyncWorker(Project project)
{
var searchTask = _currentDocument != null
? service.SearchDocumentAsync(_currentDocument, _searchPattern, _kinds, _cancellationToken)
: service.SearchProjectAsync(project, _searchPattern, _kinds, _cancellationToken);
: service.SearchProjectAsync(project, activeDocumentOpt, _searchPattern, _kinds, _cancellationToken);
var results = await searchTask.ConfigureAwait(false);
if (results != null)
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
......@@ -23,21 +24,22 @@ internal abstract partial class AbstractNavigateToSearchService
new ConditionalWeakTable<Project, Tuple<string, ImmutableArray<SearchResult>>>();
public static Task<ImmutableArray<INavigateToSearchResult>> SearchProjectInCurrentProcessAsync(
Project project, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
Project project, Document activeDocumentOpt, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
{
return FindSearchResultsAsync(
project, searchDocument: null, pattern: searchPattern, kinds, cancellationToken: cancellationToken);
project, activeDocumentOpt, searchDocument: null, pattern: searchPattern, kinds, cancellationToken: cancellationToken);
}
public static Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentInCurrentProcessAsync(
Document document, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
{
return FindSearchResultsAsync(
document.Project, document, searchPattern, kinds, cancellationToken);
document.Project, activeDocumentOpt: null, document, searchPattern, kinds, cancellationToken);
}
private static async Task<ImmutableArray<INavigateToSearchResult>> FindSearchResultsAsync(
Project project, Document searchDocument, string pattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
Project project, Document activeDocumentOpt, Document searchDocument,
string pattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
{
// If the user created a dotted pattern then we'll grab the last part of the name
var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(pattern);
......@@ -66,8 +68,8 @@ internal abstract partial class AbstractNavigateToSearchService
// scratch.
#if true
var task = searchDocument != null
? ComputeSearchResultsAsync(project, searchDocument, nameMatcher, containerMatcherOpt, declaredSymbolInfoKindsSet, nameMatches, containerMatches, cancellationToken)
: TryFilterPreviousSearchResultsAsync(project, searchDocument, pattern, nameMatcher, containerMatcherOpt, declaredSymbolInfoKindsSet, nameMatches, containerMatches, cancellationToken);
? ComputeSearchResultsAsync(project, activeDocumentOpt, searchDocument, nameMatcher, containerMatcherOpt, declaredSymbolInfoKindsSet, nameMatches, containerMatches, cancellationToken)
: TryFilterPreviousSearchResultsAsync(project, activeDocumentOpt, searchDocument, pattern, nameMatcher, containerMatcherOpt, declaredSymbolInfoKindsSet, nameMatches, containerMatches, cancellationToken);
#else
var task = ComputeSearchResultsAsync(project, searchDocument, nameMatcher, containerMatcherOpt, declaredSymbolInfoKindsSet, nameMatches, containerMatches, cancellationToken);
#endif
......@@ -84,7 +86,7 @@ internal abstract partial class AbstractNavigateToSearchService
}
private static async Task<ImmutableArray<SearchResult>> TryFilterPreviousSearchResultsAsync(
Project project, Document searchDocument, string pattern,
Project project, Document activeDocumentOpt, Document searchDocument, string pattern,
PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt,
DeclaredSymbolInfoKindSet kinds,
ArrayBuilder<PatternMatch> nameMatches, ArrayBuilder<PatternMatch> containerMatches,
......@@ -111,9 +113,8 @@ internal abstract partial class AbstractNavigateToSearchService
// Didn't have previous results. Or it was a very different pattern.
// Can't reuse.
searchResults = await ComputeSearchResultsAsync(
project, searchDocument,
nameMatcher, containerMatcherOpt,
kinds,
project, activeDocumentOpt, searchDocument,
nameMatcher, containerMatcherOpt, kinds,
nameMatches, containerMatches, cancellationToken).ConfigureAwait(false);
}
......@@ -152,14 +153,21 @@ internal abstract partial class AbstractNavigateToSearchService
}
private static async Task<ImmutableArray<SearchResult>> ComputeSearchResultsAsync(
Project project, Document searchDocument,
Project project, Document activeDocumentOpt, Document searchDocument,
PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt,
DeclaredSymbolInfoKindSet kinds,
ArrayBuilder<PatternMatch> nameMatches, ArrayBuilder<PatternMatch> containerMatches,
CancellationToken cancellationToken)
{
var result = ArrayBuilder<SearchResult>.GetInstance();
foreach (var document in project.Documents)
// Prioritize the active document if we have one.
var documents = activeDocumentOpt == null
? project.Documents
: project.Documents.Where(d => d == activeDocumentOpt)
.Concat(project.Documents.Where(d => d != activeDocumentOpt));
foreach (var document in documents)
{
if (searchDocument != null && document != searchDocument)
{
......
......@@ -25,13 +25,13 @@ internal abstract partial class AbstractNavigateToSearchService
}
private async Task<ImmutableArray<INavigateToSearchResult>> SearchProjectInRemoteProcessAsync(
RemoteHostClient client, Project project, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
RemoteHostClient client, Project project, Document activeDocumentOpt, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
{
var solution = project.Solution;
var serializableResults = await client.TryRunCodeAnalysisRemoteAsync<IList<SerializableNavigateToSearchResult>>(
solution, nameof(IRemoteNavigateToSearchService.SearchProjectAsync),
new object[] { project.Id, searchPattern, kinds.ToArray() }, cancellationToken).ConfigureAwait(false);
new object[] { project.Id, activeDocumentOpt?.Id, searchPattern, kinds.ToArray() }, cancellationToken).ConfigureAwait(false);
return serializableResults.SelectAsArray(r => r.Rehydrate(solution));
}
......
......@@ -42,18 +42,18 @@ internal abstract partial class AbstractNavigateToSearchService : INavigateToSea
}
public async Task<ImmutableArray<INavigateToSearchResult>> SearchProjectAsync(
Project project, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
Project project, Document activeDocumentOpt, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken)
{
var client = await TryGetRemoteHostClientAsync(project, cancellationToken).ConfigureAwait(false);
if (client == null)
{
return await SearchProjectInCurrentProcessAsync(
project, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
project, activeDocumentOpt, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
}
else
{
return await SearchProjectInRemoteProcessAsync(
client, project, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
client, activeDocumentOpt, project, searchPattern, kinds, cancellationToken).ConfigureAwait(false);
}
}
}
......
......@@ -28,7 +28,7 @@ bool CanFilter
get;
}
Task<ImmutableArray<INavigateToSearchResult>> SearchProjectAsync(Project project, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken);
Task<ImmutableArray<INavigateToSearchResult>> SearchProjectAsync(Project project, Document activeDocumentOpt, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken);
Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentAsync(Document document, string searchPattern, IImmutableSet<string> kinds, CancellationToken cancellationToken);
}
}
......@@ -10,6 +10,6 @@ namespace Microsoft.CodeAnalysis.NavigateTo
internal interface IRemoteNavigateToSearchService
{
Task<IList<SerializableNavigateToSearchResult>> SearchDocumentAsync(DocumentId documentId, string searchPattern, string[] kinds, CancellationToken cancellationToken);
Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(ProjectId projectId, string searchPattern, string[] kinds, CancellationToken cancellationToken);
Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(ProjectId projectId, DocumentId activeDocumentIdOpt, string searchPattern, string[] kinds, CancellationToken cancellationToken);
}
}
......@@ -29,7 +29,7 @@ internal partial class CodeAnalysisService : IRemoteNavigateToSearchService
}
public Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(
ProjectId projectId, string searchPattern, string[] kinds, CancellationToken cancellationToken)
ProjectId projectId, DocumentId activeDocIdOpt, string searchPattern, string[] kinds, CancellationToken cancellationToken)
{
return RunServiceAsync(async token =>
{
......@@ -38,8 +38,10 @@ internal partial class CodeAnalysisService : IRemoteNavigateToSearchService
var solution = await GetSolutionAsync(token).ConfigureAwait(false);
var project = solution.GetProject(projectId);
var activeDocumentOpt = solution.GetDocument(activeDocIdOpt);
var result = await AbstractNavigateToSearchService.SearchProjectInCurrentProcessAsync(
project, searchPattern, kinds.ToImmutableHashSet(), token).ConfigureAwait(false);
project, activeDocumentOpt, searchPattern, kinds.ToImmutableHashSet(), token).ConfigureAwait(false);
return Convert(result);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册