提交 5eaae79c 编写于 作者: C CyrusNajmabadi

Cleanup code.

上级 38a7837e
......@@ -126,7 +126,7 @@ private IStreamingFindUsagesPresenter GetStreamingPresenter()
// Let the presented know we're starging a search. It will give us back
// the context object that the FAR service will push results into.
var context = presenter.StartSearch(
EditorFeaturesResources.Find_References, canShowReferences: true);
EditorFeaturesResources.Find_References, supportsReferences: true);
await findUsagesService.FindReferencesAsync(document, caretPosition, context).ConfigureAwait(false);
// Note: we don't need to put this in a finally. The only time we might not hit
......
......@@ -21,7 +21,13 @@ internal interface IStreamingFindUsagesPresenter
/// search completes <see cref="FindUsagesContext.OnCompletedAsync"/> should be called.
/// etc. etc.
/// </summary>
FindUsagesContext StartSearch(string title, bool canShowReferences);
/// <param name="title">A title to display to the user in the presentation of the results.</param>
/// <param name="supportsReferences">Whether or not showing references is supported.
/// If true, then the presenter can group by definition, showing references underneath.
/// It can also show messages about no references being found at the end of the search.
/// If false, the presenter will not group by definitions, and will show the definition
/// items in isolation.</param>
FindUsagesContext StartSearch(string title, bool supportsReferences);
}
internal static class IStreamingFindUsagesPresenterExtensions
......@@ -65,8 +71,7 @@ internal static class IStreamingFindUsagesPresenterExtensions
{
// We have multiple definitions, or we have definitions with multiple locations.
// Present this to the user so they can decide where they want to go to.
var context = presenter.StartSearch(title, canShowReferences: false);
var context = presenter.StartSearch(title, supportsReferences: false);
foreach (var definition in nonExternalItems)
{
await context.OnDefinitionFoundAsync(definition).ConfigureAwait(false);
......
......@@ -14,244 +14,249 @@
namespace Microsoft.VisualStudio.LanguageServices.FindUsages
{
internal class WithReferencesFindUsagesContext : AbstractTableDataSourceFindUsagesContext
/// <summary>
/// Context to be used for FindAllReferences (as opposed to FindImplementations/GoToDef).
/// This context supports showing reference items, and will display appropriate messages
/// about no-references being found for a definition at the end of the search.
/// </summary>
internal class WithReferencesFindUsagesContext : AbstractTableDataSourceFindUsagesContext
{
public WithReferencesFindUsagesContext(
StreamingFindUsagesPresenter presenter,
IFindAllReferencesWindow findReferencesWindow)
: base(presenter, findReferencesWindow)
{
public WithReferencesFindUsagesContext(
StreamingFindUsagesPresenter presenter,
IFindAllReferencesWindow findReferencesWindow)
: base(presenter, findReferencesWindow)
{
}
}
protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
{
// If this is a definition we always want to show, then create entries
// for all the declaration locations immediately. Otherwise, we'll
// create them on demand when we hear about references for this definition.
if (definition.DisplayIfNoReferences)
{
// If this is a definition we always want to show, then create entries
// for all the declaration locations immediately. Otherwise, we'll
// create them on demand when we hear about references for this definition.
if (definition.DisplayIfNoReferences)
{
await AddDeclarationEntriesAsync(definition).ConfigureAwait(false);
}
await AddDeclarationEntriesAsync(definition).ConfigureAwait(false);
}
}
private async Task AddDeclarationEntriesAsync(DefinitionItem definition)
{
CancellationToken.ThrowIfCancellationRequested();
// Don't do anything if we already have declaration entries for this definition
// (i.e. another thread beat us to this).
if (HasDeclarationEntries(definition))
{
return;
}
var definitionBucket = GetOrCreateDefinitionBucket(definition);
// We could do this inside the lock. but that would mean async activity in a
// lock, and i'd like to avoid that. That does mean that we might do extra
// work if multiple threads end up down htis path. But only one of them will
// win when we access the lock below.
var declarations = ArrayBuilder<Entry>.GetInstance();
foreach (var declarationLocation in definition.SourceSpans)
{
var definitionEntry = await CreateDocumentSpanEntryAsync(
definitionBucket, declarationLocation, isDefinitionLocation: true).ConfigureAwait(false);
if (definitionEntry != null)
{
declarations.Add(definitionEntry);
}
}
private async Task AddDeclarationEntriesAsync(DefinitionItem definition)
{
CancellationToken.ThrowIfCancellationRequested();
var changed = false;
lock (_gate)
{
// Do one final check to ensure that no other thread beat us here.
if (!HasDeclarationEntries(definition))
{
// We only include declaration entries in the entries we show when
// not grouping by definition.
_entriesWhenNotGroupingByDefinition = _entriesWhenNotGroupingByDefinition.AddRange(declarations);
CurrentVersionNumber++;
changed = true;
}
}
// Don't do anything if we already have declaration entries for this definition
// (i.e. another thread beat us to this).
if (HasDeclarationEntries(definition))
{
return;
}
declarations.Free();
var definitionBucket = GetOrCreateDefinitionBucket(definition);
if (changed)
// We could do this inside the lock. but that would mean async activity in a
// lock, and i'd like to avoid that. That does mean that we might do extra
// work if multiple threads end up down htis path. But only one of them will
// win when we access the lock below.
var declarations = ArrayBuilder<Entry>.GetInstance();
foreach (var declarationLocation in definition.SourceSpans)
{
var definitionEntry = await CreateDocumentSpanEntryAsync(
definitionBucket, declarationLocation, isDefinitionLocation: true).ConfigureAwait(false);
if (definitionEntry != null)
{
// Let all our subscriptions know that we've updated.
NotifyChange();
declarations.Add(definitionEntry);
}
}
private bool HasDeclarationEntries(DefinitionItem definition)
var changed = false;
lock (_gate)
{
lock (_gate)
// Do one final check to ensure that no other thread beat us here.
if (!HasDeclarationEntries(definition))
{
return _entriesWhenNotGroupingByDefinition.Any(
e => e.DefinitionBucket.DefinitionItem == definition);
// We only include declaration entries in the entries we show when
// not grouping by definition.
_entriesWhenNotGroupingByDefinition = _entriesWhenNotGroupingByDefinition.AddRange(declarations);
CurrentVersionNumber++;
changed = true;
}
}
protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
declarations.Free();
if (changed)
{
// Normal references go into both sets of entries.
return OnEntryFoundAsync(
reference.Definition,
bucket => CreateDocumentSpanEntryAsync(
bucket, reference.SourceSpan, isDefinitionLocation: false),
addToEntriesWhenGroupingByDefinition: true,
addToEntriesWhenNotGroupingByDefinition: true);
// Let all our subscriptions know that we've updated.
NotifyChange();
}
}
protected async Task OnEntryFoundAsync(
DefinitionItem definition,
Func<RoslynDefinitionBucket, Task<Entry>> createEntryAsync,
bool addToEntriesWhenGroupingByDefinition,
bool addToEntriesWhenNotGroupingByDefinition)
private bool HasDeclarationEntries(DefinitionItem definition)
{
lock (_gate)
{
Debug.Assert(addToEntriesWhenGroupingByDefinition || addToEntriesWhenNotGroupingByDefinition);
CancellationToken.ThrowIfCancellationRequested();
// Ok, we got a *reference* to some definition item. This may have been
// a reference for some definition that we haven't created any declaration
// entries for (i.e. becuase it had DisplayIfNoReferences = false). Because
// we've now found a reference, we want to make sure all its declaration
// entries are added.
await AddDeclarationEntriesAsync(definition).ConfigureAwait(false);
return _entriesWhenNotGroupingByDefinition.Any(
e => e.DefinitionBucket.DefinitionItem == definition);
}
}
// First find the bucket corresponding to our definition.
var definitionBucket = GetOrCreateDefinitionBucket(definition);
var entry = await createEntryAsync(definitionBucket).ConfigureAwait(false);
protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
{
// Normal references go into both sets of entries.
return OnEntryFoundAsync(
reference.Definition,
bucket => CreateDocumentSpanEntryAsync(
bucket, reference.SourceSpan, isDefinitionLocation: false),
addToEntriesWhenGroupingByDefinition: true,
addToEntriesWhenNotGroupingByDefinition: true);
}
lock (_gate)
{
// Once we can make the new entry, add it to the appropriate list.
if (addToEntriesWhenGroupingByDefinition)
{
_entriesWhenGroupingByDefinition = _entriesWhenGroupingByDefinition.Add(entry);
}
protected async Task OnEntryFoundAsync(
DefinitionItem definition,
Func<RoslynDefinitionBucket, Task<Entry>> createEntryAsync,
bool addToEntriesWhenGroupingByDefinition,
bool addToEntriesWhenNotGroupingByDefinition)
{
Debug.Assert(addToEntriesWhenGroupingByDefinition || addToEntriesWhenNotGroupingByDefinition);
CancellationToken.ThrowIfCancellationRequested();
if (addToEntriesWhenNotGroupingByDefinition)
{
_entriesWhenNotGroupingByDefinition = _entriesWhenNotGroupingByDefinition.Add(entry);
}
// Ok, we got a *reference* to some definition item. This may have been
// a reference for some definition that we haven't created any declaration
// entries for (i.e. becuase it had DisplayIfNoReferences = false). Because
// we've now found a reference, we want to make sure all its declaration
// entries are added.
await AddDeclarationEntriesAsync(definition).ConfigureAwait(false);
CurrentVersionNumber++;
// First find the bucket corresponding to our definition.
var definitionBucket = GetOrCreateDefinitionBucket(definition);
var entry = await createEntryAsync(definitionBucket).ConfigureAwait(false);
lock (_gate)
{
// Once we can make the new entry, add it to the appropriate list.
if (addToEntriesWhenGroupingByDefinition)
{
_entriesWhenGroupingByDefinition = _entriesWhenGroupingByDefinition.Add(entry);
}
// Let all our subscriptions know that we've updated.
NotifyChange();
if (addToEntriesWhenNotGroupingByDefinition)
{
_entriesWhenNotGroupingByDefinition = _entriesWhenNotGroupingByDefinition.Add(entry);
}
CurrentVersionNumber++;
}
protected override async Task OnCompletedAsyncWorkerAsync()
// Let all our subscriptions know that we've updated.
NotifyChange();
}
protected override async Task OnCompletedAsyncWorkerAsync()
{
// Now that we know the search is over, create and display any error messages
// for definitions that were not found.
await CreateMissingReferenceEntriesIfNecessaryAsync().ConfigureAwait(false);
await CreateNoResultsFoundEntryIfNecessaryAsync().ConfigureAwait(false);
}
private async Task CreateMissingReferenceEntriesIfNecessaryAsync()
{
await CreateMissingReferenceEntriesIfNecessaryAsync(whenGroupingByDefinition: true).ConfigureAwait(false);
await CreateMissingReferenceEntriesIfNecessaryAsync(whenGroupingByDefinition: false).ConfigureAwait(false);
}
private async Task CreateMissingReferenceEntriesIfNecessaryAsync(
bool whenGroupingByDefinition)
{
// Go through and add dummy entries for any definitions that
// that we didn't find any references for.
var definitions = GetDefinitionsToCreateMissingReferenceItemsFor(whenGroupingByDefinition);
foreach (var definition in definitions)
{
// Now that we know the search is over, create and display any error messages
// for definitions that were not found.
await CreateMissingReferenceEntriesIfNecessaryAsync().ConfigureAwait(false);
await CreateNoResultsFoundEntryIfNecessaryAsync().ConfigureAwait(false);
// Create a fake reference to this definition that says
// "no references found to <symbolname>".
await OnEntryFoundAsync(definition,
bucket => SimpleMessageEntry.CreateAsync(
bucket, GetMessage(bucket.DefinitionItem)),
addToEntriesWhenGroupingByDefinition: whenGroupingByDefinition,
addToEntriesWhenNotGroupingByDefinition: !whenGroupingByDefinition).ConfigureAwait(false);
}
}
private async Task CreateMissingReferenceEntriesIfNecessaryAsync()
private static string GetMessage(DefinitionItem definition)
{
if (definition.IsExternal)
{
await CreateMissingReferenceEntriesIfNecessaryAsync(whenGroupingByDefinition: true).ConfigureAwait(false);
await CreateMissingReferenceEntriesIfNecessaryAsync(whenGroupingByDefinition: false).ConfigureAwait(false);
return ServicesVisualStudioNextResources.External_reference_found;
}
private async Task CreateMissingReferenceEntriesIfNecessaryAsync(
bool whenGroupingByDefinition)
{
// Go through and add dummy entries for any definitions that
// that we didn't find any references for.
return string.Format(
ServicesVisualStudioNextResources.No_references_found_to_0,
definition.NameDisplayParts.JoinText());
}
var definitions = GetDefinitionsToCreateMissingReferenceItemsFor(whenGroupingByDefinition);
foreach (var definition in definitions)
private ImmutableArray<DefinitionItem> GetDefinitionsToCreateMissingReferenceItemsFor(
bool whenGroupingByDefinition)
{
lock (_gate)
{
var entries = whenGroupingByDefinition
? _entriesWhenGroupingByDefinition
: _entriesWhenNotGroupingByDefinition;
// Find any definitions that we didn't have any references to. But only show
// them if they want to be displayed without any references. This will
// ensure that we still see things like overrides and whatnot, but we
// won't show property-accessors.
var seenDefinitions = entries.Select(r => r.DefinitionBucket.DefinitionItem).ToSet();
var q = from definition in _definitions
where !seenDefinitions.Contains(definition) &&
definition.DisplayIfNoReferences
select definition;
// If we find at least one of these types of definitions, then just return those.
var result = ImmutableArray.CreateRange(q);
if (result.Length > 0)
{
// Create a fake reference to this definition that says
// "no references found to <symbolname>".
await OnEntryFoundAsync(definition,
bucket => SimpleMessageEntry.CreateAsync(
bucket, GetMessage(bucket.DefinitionItem)),
addToEntriesWhenGroupingByDefinition: whenGroupingByDefinition,
addToEntriesWhenNotGroupingByDefinition: !whenGroupingByDefinition).ConfigureAwait(false);
return result;
}
}
private static string GetMessage(DefinitionItem definition)
{
if (definition.IsExternal)
// We found no definitions that *want* to be displayed. However, we still
// want to show something. So, if necessary, show at lest the first definition
// even if we found no references and even if it would prefer to not be seen.
if (entries.Count == 0 && _definitions.Count > 0)
{
return ServicesVisualStudioNextResources.External_reference_found;
return ImmutableArray.Create(_definitions.First());
}
return string.Format(
ServicesVisualStudioNextResources.No_references_found_to_0,
definition.NameDisplayParts.JoinText());
return ImmutableArray<DefinitionItem>.Empty;
}
}
private ImmutableArray<DefinitionItem> GetDefinitionsToCreateMissingReferenceItemsFor(
bool whenGroupingByDefinition)
private async Task CreateNoResultsFoundEntryIfNecessaryAsync()
{
bool noDefinitions;
lock (_gate)
{
lock (_gate)
{
var entries = whenGroupingByDefinition
? _entriesWhenGroupingByDefinition
: _entriesWhenNotGroupingByDefinition;
// Find any definitions that we didn't have any references to. But only show
// them if they want to be displayed without any references. This will
// ensure that we still see things like overrides and whatnot, but we
// won't show property-accessors.
var seenDefinitions = entries.Select(r => r.DefinitionBucket.DefinitionItem).ToSet();
var q = from definition in _definitions
where !seenDefinitions.Contains(definition) &&
definition.DisplayIfNoReferences
select definition;
// If we find at least one of these types of definitions, then just return those.
var result = ImmutableArray.CreateRange(q);
if (result.Length > 0)
{
return result;
}
// We found no definitions that *want* to be displayed. However, we still
// want to show something. So, if necessary, show at lest the first definition
// even if we found no references and even if it would prefer to not be seen.
if (entries.Count == 0 && _definitions.Count > 0)
{
return ImmutableArray.Create(_definitions.First());
}
return ImmutableArray<DefinitionItem>.Empty;
}
noDefinitions = this._definitions.Count == 0;
}
private async Task CreateNoResultsFoundEntryIfNecessaryAsync()
if (noDefinitions)
{
bool noDefinitions;
lock (_gate)
{
noDefinitions = this._definitions.Count == 0;
}
if (noDefinitions)
{
// Create a fake definition/reference called "search found no results"
await OnEntryFoundAsync(NoResultsDefinitionItem,
bucket => SimpleMessageEntry.CreateAsync(
bucket, ServicesVisualStudioNextResources.Search_found_no_results),
addToEntriesWhenGroupingByDefinition: true,
addToEntriesWhenNotGroupingByDefinition: true).ConfigureAwait(false);
}
// Create a fake definition/reference called "search found no results"
await OnEntryFoundAsync(NoResultsDefinitionItem,
bucket => SimpleMessageEntry.CreateAsync(
bucket, ServicesVisualStudioNextResources.Search_found_no_results),
addToEntriesWhenGroupingByDefinition: true,
addToEntriesWhenNotGroupingByDefinition: true).ConfigureAwait(false);
}
private static readonly DefinitionItem NoResultsDefinitionItem =
DefinitionItem.CreateNonNavigableItem(
GlyphTags.GetTags(Glyph.StatusInformation),
ImmutableArray.Create(new TaggedText(
TextTags.Text,
ServicesVisualStudioNextResources.Search_found_no_results)));
}
private static readonly DefinitionItem NoResultsDefinitionItem =
DefinitionItem.CreateNonNavigableItem(
GlyphTags.GetTags(Glyph.StatusInformation),
ImmutableArray.Create(new TaggedText(
TextTags.Text,
ServicesVisualStudioNextResources.Search_found_no_results)));
}
}
\ No newline at end of file
......@@ -9,75 +9,82 @@
namespace Microsoft.VisualStudio.LanguageServices.FindUsages
{
internal class WithoutReferencesFindUsagesContext : AbstractTableDataSourceFindUsagesContext
/// <summary>
/// Context to be used for FindImplementations/GoToDef (as opposed to FindReferences).
/// This context will not group entries by definition, and will instead just create
/// entries for the definitions themselves.
/// </summary>
internal class WithoutReferencesFindUsagesContext : AbstractTableDataSourceFindUsagesContext
{
public WithoutReferencesFindUsagesContext(
StreamingFindUsagesPresenter presenter,
IFindAllReferencesWindow findReferencesWindow)
: base(presenter, findReferencesWindow)
{
public WithoutReferencesFindUsagesContext(
StreamingFindUsagesPresenter presenter,
IFindAllReferencesWindow findReferencesWindow)
: base(presenter, findReferencesWindow)
{
}
}
protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
=> throw new InvalidOperationException();
// We should never be called in a context where we get references.
protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
=> throw new InvalidOperationException();
protected override Task OnCompletedAsyncWorkerAsync()
=> SpecializedTasks.EmptyTask;
// Nothing to do on completion.
protected override Task OnCompletedAsyncWorkerAsync()
=> SpecializedTasks.EmptyTask;
protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
{
var definitionBucket = GetOrCreateDefinitionBucket(definition);
protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
{
var definitionBucket = GetOrCreateDefinitionBucket(definition);
var entries = ArrayBuilder<Entry>.GetInstance();
try
var entries = ArrayBuilder<Entry>.GetInstance();
try
{
if (definition.SourceSpans.Length == 1)
{
if (definition.SourceSpans.Length == 1)
// If we only have a single location, then use the DisplayParts of the
// definition as what to show. That way we show enough information for things
// methods. i.e. we'll show "void TypeName.MethodName(args...)" allowing
// the user to see the type the method was created in.
var entry = await CreateEntryAsync(definitionBucket, definition).ConfigureAwait(false);
entries.Add(entry);
}
else
{
// If we have multiple spans (i.e. for partial types), then create a
// DocumentSpanEntry for each. That way we can easily see the source
// code where each location is to help the user decide which they want
// to navigate to.
foreach (var sourceSpan in definition.SourceSpans)
{
// If we only have a single location, then use the DisplayParts of the
// definition as what to show. That way we show enough information for things
// methods. i.e. we'll show "void TypeName.MethodName(args...)" allowing
// the user to see the type the method was created in.
var entry = await CreateEntryAsync(definitionBucket, definition).ConfigureAwait(false);
var entry = await CreateDocumentSpanEntryAsync(
definitionBucket, sourceSpan, isDefinitionLocation: true).ConfigureAwait(false);
entries.Add(entry);
}
else
{
// If we have multiple spans (i.e. for partial types), then create a
// DocumentSpanEntry for each. That way we can easily see the source
// code where each location is to help the user decide which they want
// to navigate to.
foreach (var sourceSpan in definition.SourceSpans)
{
var entry = await CreateDocumentSpanEntryAsync(
definitionBucket, sourceSpan, isDefinitionLocation: true).ConfigureAwait(false);
entries.Add(entry);
}
}
}
if (entries.Count > 0)
if (entries.Count > 0)
{
lock (_gate)
{
lock (_gate)
{
_entriesWhenGroupingByDefinition = _entriesWhenGroupingByDefinition.AddRange(entries);
_entriesWhenNotGroupingByDefinition = _entriesWhenNotGroupingByDefinition.AddRange(entries);
}
this.NotifyChange();
_entriesWhenGroupingByDefinition = _entriesWhenGroupingByDefinition.AddRange(entries);
_entriesWhenNotGroupingByDefinition = _entriesWhenNotGroupingByDefinition.AddRange(entries);
}
}
finally
{
entries.Free();
this.NotifyChange();
}
}
private async Task<Entry> CreateEntryAsync(
RoslynDefinitionBucket definitionBucket, DefinitionItem definition)
finally
{
var documentSpan = definition.SourceSpans[0];
var (guid, sourceText) = await GetGuidAndSourceTextAsync(documentSpan.Document).ConfigureAwait(false);
return new DefinitionItemEntry(this, definitionBucket, documentSpan, guid, sourceText);
entries.Free();
}
}
private async Task<Entry> CreateEntryAsync(
RoslynDefinitionBucket definitionBucket, DefinitionItem definition)
{
var documentSpan = definition.SourceSpans[0];
var (guid, sourceText) = await GetGuidAndSourceTextAsync(documentSpan.Document).ConfigureAwait(false);
return new DefinitionItemEntry(this, definitionBucket, documentSpan, guid, sourceText);
}
}
}
\ No newline at end of file
// 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.Windows;
using System.Windows.Documents;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Shell.TableControl;
using Microsoft.VisualStudio.Shell.TableManager;
namespace Microsoft.VisualStudio.LanguageServices.FindUsages
{
internal abstract class AbstractDocumentSpanEntry : Entry
/// <summary>
/// Base type of all <see cref="Entry"/>s that represent some source location in
/// a <see cref="Document"/>. Navigation to that location is provided by this type.
/// Subclasses can be used to provide customized line text to display in the entry.
/// </summary>
internal abstract class AbstractDocumentSpanEntry : Entry
{
private readonly AbstractTableDataSourceFindUsagesContext _context;
private readonly DocumentSpan _documentSpan;
private readonly object _boxedProjectGuid;
protected readonly SourceText _sourceText;
protected AbstractDocumentSpanEntry(
AbstractTableDataSourceFindUsagesContext context,
RoslynDefinitionBucket definitionBucket,
DocumentSpan documentSpan,
Guid projectGuid,
SourceText sourceText)
: base(definitionBucket)
{
private readonly AbstractTableDataSourceFindUsagesContext _context;
private readonly DocumentSpan _documentSpan;
private readonly object _boxedProjectGuid;
protected readonly SourceText _sourceText;
protected AbstractDocumentSpanEntry(
AbstractTableDataSourceFindUsagesContext context,
RoslynDefinitionBucket definitionBucket,
DocumentSpan documentSpan,
Guid projectGuid,
SourceText sourceText)
: base(definitionBucket)
{
_context = context;
_context = context;
_documentSpan = documentSpan;
_boxedProjectGuid = projectGuid;
_sourceText = sourceText;
}
_documentSpan = documentSpan;
_boxedProjectGuid = projectGuid;
_sourceText = sourceText;
}
protected StreamingFindUsagesPresenter Presenter => _context.Presenter;
protected StreamingFindUsagesPresenter Presenter => _context.Presenter;
protected Document Document => _documentSpan.Document;
protected TextSpan SourceSpan => _documentSpan.SourceSpan;
protected Document Document => _documentSpan.Document;
protected TextSpan SourceSpan => _documentSpan.SourceSpan;
protected override object GetValueWorker(string keyName)
protected override object GetValueWorker(string keyName)
{
switch (keyName)
{
switch (keyName)
{
case StandardTableKeyNames.DocumentName:
return Document.FilePath;
case StandardTableKeyNames.Line:
return _sourceText.Lines.GetLinePosition(SourceSpan.Start).Line;
case StandardTableKeyNames.Column:
return _sourceText.Lines.GetLinePosition(SourceSpan.Start).Character;
case StandardTableKeyNames.ProjectName:
return Document.Project.Name;
case StandardTableKeyNames.ProjectGuid:
return _boxedProjectGuid;
case StandardTableKeyNames.Text:
return _sourceText.Lines.GetLineFromPosition(SourceSpan.Start).ToString().Trim();
}
return null;
case StandardTableKeyNames.DocumentName:
return Document.FilePath;
case StandardTableKeyNames.Line:
return _sourceText.Lines.GetLinePosition(SourceSpan.Start).Line;
case StandardTableKeyNames.Column:
return _sourceText.Lines.GetLinePosition(SourceSpan.Start).Character;
case StandardTableKeyNames.ProjectName:
return Document.Project.Name;
case StandardTableKeyNames.ProjectGuid:
return _boxedProjectGuid;
case StandardTableKeyNames.Text:
return _sourceText.Lines.GetLineFromPosition(SourceSpan.Start).ToString().Trim();
}
return null;
}
public sealed override bool TryCreateColumnContent(string columnName, out FrameworkElement content)
{
if (columnName == StandardTableColumnDefinitions2.LineText)
{
var inlines = CreateLineTextInlines();
var textBlock = inlines.ToTextBlock(Presenter.TypeMap, wrap: false);
content = textBlock;
return true;
}
content = null;
return false;
}
protected abstract IList<Inline> CreateLineTextInlines();
}
}
\ No newline at end of file
// 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.Windows;
using System.Collections.Generic;
using System.Windows.Documents;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Shell.TableControl;
namespace Microsoft.VisualStudio.LanguageServices.FindUsages
{
internal class DefinitionItemEntry : AbstractDocumentSpanEntry
/// <summary>
/// Shows a DefinitionItem as a Row in the FindReferencesWindow. Only used for
/// GoToDefinition/FindImplementations. In these operations, we don't want to
/// create a DefinitionBucket. So we instead just so the symbol as a normal row.
/// </summary>
internal class DefinitionItemEntry : AbstractDocumentSpanEntry
{
public DefinitionItemEntry(
AbstractTableDataSourceFindUsagesContext context,
RoslynDefinitionBucket definitionBucket,
DocumentSpan documentSpan,
Guid projectGuid,
SourceText sourceText)
: base(context, definitionBucket, documentSpan, projectGuid, sourceText)
{
public DefinitionItemEntry(
AbstractTableDataSourceFindUsagesContext context,
RoslynDefinitionBucket definitionBucket,
DocumentSpan documentSpan,
Guid projectGuid,
SourceText sourceText)
: base(context, definitionBucket, documentSpan, projectGuid, sourceText)
{
}
public override bool TryCreateColumnContent(string columnName, out FrameworkElement content)
{
if (columnName == StandardTableColumnDefinitions2.LineText)
{
var inlines = DefinitionBucket.DefinitionItem.DisplayParts.ToInlines(Presenter.TypeMap);
var textBlock = inlines.ToTextBlock(Presenter.TypeMap, wrap: false);
content = textBlock;
return true;
}
content = null;
return false;
}
}
protected override IList<Inline> CreateLineTextInlines()
=> DefinitionBucket.DefinitionItem.DisplayParts.ToInlines(Presenter.TypeMap);
}
}
\ No newline at end of file
......@@ -25,7 +25,7 @@ namespace Microsoft.VisualStudio.LanguageServices.FindUsages
internal class DocumentSpanEntry : AbstractDocumentSpanEntry
{
private readonly bool _isDefinitionLocation;
private readonly ClassifiedSpansAndHighlightSpan _classifiedSpans;
private readonly ClassifiedSpansAndHighlightSpan _classifiedSpansAndHighlights;
public DocumentSpanEntry(
AbstractTableDataSourceFindUsagesContext context,
......@@ -38,52 +38,31 @@ internal class DocumentSpanEntry : AbstractDocumentSpanEntry
: base(context, definitionBucket, documentSpan, projectGuid, sourceText)
{
_isDefinitionLocation = isDefinitionLocation;
_classifiedSpans = classifiedSpans;
_classifiedSpansAndHighlights = classifiedSpans;
}
public override bool TryCreateColumnContent(string columnName, out FrameworkElement content)
{
if (columnName == StandardTableColumnDefinitions2.LineText)
{
var inlines = GetHighlightedInlines(Presenter, _sourceText, _classifiedSpans, _isDefinitionLocation);
var textBlock = inlines.ToTextBlock(Presenter.TypeMap, wrap: false);
LazyToolTip.AttachTo(textBlock, CreateDisposableToolTip);
content = textBlock;
return true;
}
content = null;
return false;
}
private static IList<System.Windows.Documents.Inline> GetHighlightedInlines(
StreamingFindUsagesPresenter presenter,
SourceText sourceText,
ClassifiedSpansAndHighlightSpan classifiedSpansAndHighlight,
bool isDefinition)
{
var propertyId = isDefinition
protected override IList<System.Windows.Documents.Inline> CreateLineTextInlines()
{
var propertyId = _isDefinitionLocation
? DefinitionHighlightTag.TagId
: ReferenceHighlightTag.TagId;
var properties = presenter.FormatMapService
var properties = Presenter.FormatMapService
.GetEditorFormatMap("text")
.GetProperties(propertyId);
var highlightBrush = properties["Background"] as Brush;
var classifiedSpans = classifiedSpansAndHighlight.ClassifiedSpans;
var classifiedSpans = _classifiedSpansAndHighlights.ClassifiedSpans;
var classifiedTexts = classifiedSpans.SelectAsArray(
cs => new ClassifiedText(cs.ClassificationType, sourceText.ToString(cs.TextSpan)));
cs => new ClassifiedText(cs.ClassificationType, _sourceText.ToString(cs.TextSpan)));
var inlines = classifiedTexts.ToInlines(
presenter.TypeMap,
Presenter.TypeMap,
runCallback: (run, classifiedText, position) =>
{
if (highlightBrush != null)
{
if (position == classifiedSpansAndHighlight.HighlightSpan.Start)
if (position == _classifiedSpansAndHighlights.HighlightSpan.Start)
{
run.SetValue(
System.Windows.Documents.TextElement.BackgroundProperty,
......
......@@ -28,16 +28,16 @@ internal partial class StreamingFindUsagesPresenter :
private readonly IServiceProvider _serviceProvider;
private readonly IFindAllReferencesService _vsFindAllReferencesService;
private readonly VisualStudioWorkspace _workspace;
public readonly ITextBufferFactoryService TextBufferFactoryService;
public readonly IProjectionBufferFactoryService ProjectionBufferFactoryService;
public readonly IEditorOptionsFactoryService EditorOptionsFactoryService;
public readonly ITextEditorFactoryService TextEditorFactoryService;
public readonly IContentTypeRegistryService ContentTypeRegistryService;
public readonly IEditorFormatMapService FormatMapService;
public readonly ClassificationTypeMap TypeMap;
public readonly IEditorFormatMapService FormatMapService;
private readonly IFindAllReferencesService _vsFindAllReferencesService;
private readonly VisualStudioWorkspace _workspace;
[ImportingConstructor]
public StreamingFindUsagesPresenter(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册