未验证 提交 a90cf45f 编写于 作者: A Andrew Hall 提交者: GitHub

Allow the provisional tab to receive focus (#43586)

Sometimes we do want the preview/provisional tab to receive focus. For example, when navigating to definition of a symbol and there's only one definition.

Fixes #43585
上级 2401db9e
......@@ -64,7 +64,10 @@ internal static class IStreamingFindUsagesPresenterExtensions
var externalItems = definitions.WhereAsArray(d => d.IsExternal);
foreach (var item in externalItems)
{
if (item.TryNavigateTo(workspace, isPreview: true))
// If we're directly going to a location we need to activate the preview so
// that focus follows to the new cursor position. This behavior is expected
// because we are only going to navigate once successfully
if (item.TryNavigateTo(workspace, NavigationBehavior.PreviewWithFocus))
{
return true;
}
......@@ -80,7 +83,9 @@ internal static class IStreamingFindUsagesPresenterExtensions
nonExternalItems[0].SourceSpans.Length <= 1)
{
// There was only one location to navigate to. Just directly go to that location.
return nonExternalItems[0].TryNavigateTo(workspace, isPreview: true);
// If we're directly going to a location we need to activate the preview so
// that focus follows to the new cursor position.
return nonExternalItems[0].TryNavigateTo(workspace, NavigationBehavior.PreviewWithFocus);
}
if (presenter != null)
......
......@@ -17,13 +17,16 @@ public static bool CanNavigateTo(this DocumentSpan documentSpan)
return service.CanNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan);
}
public static bool TryNavigateTo(this DocumentSpan documentSpan, bool isPreview)
public static bool TryNavigateTo(this DocumentSpan documentSpan, NavigationBehavior navigationBehavior)
{
var solution = documentSpan.Document.Project.Solution;
var workspace = solution.Workspace;
var service = workspace.Services.GetService<IDocumentNavigationService>();
return service.TryNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan,
options: solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, isPreview));
var options = solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, navigationBehavior != NavigationBehavior.Normal);
options = options.WithChangedOption(NavigationOptions.ActivateProvisionalTab, navigationBehavior == NavigationBehavior.PreviewWithFocus);
return service.TryNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan, options);
}
public static async Task<bool> IsHiddenAsync(
......
......@@ -50,7 +50,7 @@ public override bool CanNavigateTo(Workspace workspace)
return SourceSpans[0].CanNavigateTo();
}
public override bool TryNavigateTo(Workspace workspace, bool isPreview)
public override bool TryNavigateTo(Workspace workspace, NavigationBehavior navigationBehavior)
{
if (Properties.ContainsKey(NonNavigable))
{
......@@ -62,7 +62,7 @@ public override bool TryNavigateTo(Workspace workspace, bool isPreview)
return TryNavigateToMetadataSymbol(workspace, symbolKey);
}
return SourceSpans[0].TryNavigateTo(isPreview);
return SourceSpans[0].TryNavigateTo(navigationBehavior);
}
private bool CanNavigateToMetadataSymbol(Workspace workspace, string symbolKey)
......
......@@ -152,9 +152,8 @@ internal abstract partial class DefinitionItem
Contract.ThrowIfFalse(Properties.ContainsKey(MetadataSymbolOriginatingProjectIdDebugName));
}
}
public abstract bool CanNavigateTo(Workspace workspace);
public abstract bool TryNavigateTo(Workspace workspace, bool isPreview);
public abstract bool TryNavigateTo(Workspace workspace, NavigationBehavior navigationBehavior);
public static DefinitionItem Create(
ImmutableArray<string> tags,
......
......@@ -13,5 +13,12 @@ internal static class NavigationOptions
/// be used for any document that needs to be opened, if one is available.
/// </summary>
public static readonly Option2<bool> PreferProvisionalTab = new Option2<bool>(nameof(NavigationOptions), nameof(PreferProvisionalTab), defaultValue: false);
/// <summary>
/// This option can be passed to the <see cref="IDocumentNavigationService"/> APIs to request that if a provisional tab
/// <see cref="PreferProvisionalTab"/> is used the navigation should still activate the tab. Defaults to false to support
/// users not losing focus while navigating through lists such as find references.
/// </summary>
public static readonly Option2<bool> ActivateProvisionalTab = new Option2<bool>(nameof(NavigationOptions), nameof(ActivateProvisionalTab), defaultValue: false);
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis
{
internal enum NavigationBehavior
{
/// <summary>
/// The destination will attempt to open in a normal tab and activate
/// </summary>
Normal,
/// <summary>
/// The destination will navigate using a preview window and not activate that window.
/// Useful for cases where the user might be going through a list of items and we want to
/// make the context visible but not make focus changes
/// </summary>
PreviewWithoutFocus,
/// <summary>
/// The destination will navigate using a preview window and activate
/// </summary>
PreviewWithFocus
}
}
......@@ -33,7 +33,9 @@ protected override object GetValueWorker(string keyName)
}
bool ISupportsNavigation.TryNavigateTo(bool isPreview)
=> DefinitionBucket.DefinitionItem.TryNavigateTo(Presenter._workspace, isPreview);
=> DefinitionBucket.DefinitionItem.TryNavigateTo(
Presenter._workspace,
isPreview ? NavigationBehavior.PreviewWithoutFocus : NavigationBehavior.Normal);
protected override IList<Inline> CreateLineTextInlines()
=> DefinitionBucket.DefinitionItem.DisplayParts
......
......@@ -53,7 +53,9 @@ private class RoslynDefinitionBucket : DefinitionBucket, ISupportsNavigation
}
public bool TryNavigateTo(bool isPreview)
=> DefinitionItem.TryNavigateTo(_presenter._workspace, isPreview);
=> DefinitionItem.TryNavigateTo(
_presenter._workspace,
isPreview ? NavigationBehavior.PreviewWithoutFocus : NavigationBehavior.Normal);
public override bool TryGetValue(string key, out object content)
{
......
......@@ -109,7 +109,7 @@ private class ExternalDefinitionItem : DefinitionItem
public override bool CanNavigateTo(Workspace workspace) => true;
public override bool TryNavigateTo(Workspace workspace, bool isPreview)
public override bool TryNavigateTo(Workspace workspace, NavigationBehavior _)
=> TryOpenFile() && TryNavigateToPosition();
private bool TryOpenFile()
......
......@@ -346,10 +346,17 @@ private IDisposable OpenNewDocumentStateScope(OptionSet options)
return null;
}
var state = __VSNEWDOCUMENTSTATE.NDS_Provisional;
// If we're just opening the provisional tab, then do not "activate" the document
// (i.e. don't give it focus). This way if a user is just arrowing through a set
// (i.e. don't give it focus) unless specifically requested.
// This way if a user is just arrowing through a set
// of FindAllReferences results, they don't have their cursor placed into the document.
var state = __VSNEWDOCUMENTSTATE.NDS_Provisional | __VSNEWDOCUMENTSTATE.NDS_NoActivate;
if (!options.GetOption(NavigationOptions.ActivateProvisionalTab))
{
state |= __VSNEWDOCUMENTSTATE.NDS_NoActivate;
}
return new NewDocumentStateScope(state, VSConstants.NewDocumentStateReason.Navigation);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册