提交 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);
......
......@@ -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.
先完成此消息的编辑!
想要评论请 注册