Skip to content

Commit b3804f1

Browse files
Update progression work to have context menu. (#78754)
2 parents 713cd56 + 1c054b7 commit b3804f1

26 files changed

+773
-80
lines changed

src/EditorFeatures/Core/GoOrFind/AbstractGoOrFindCommandHandler.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public bool ExecuteCommand(TCommandArgs args, CommandExecutionContext context)
3636
if (!_navigationService.IsAvailable(document))
3737
return false;
3838

39-
return _navigationService.ExecuteCommand(document, caret.Value.Position);
39+
// We were called on the current snapshot of a buffer, and we have a position within that buffer.
40+
// We should never have an invalid position here, so pass "false" for allowInvalidPosition so we
41+
// blow up if some invariant was broken.
42+
return _navigationService.ExecuteCommand(document, caret.Value.Position, allowInvalidPosition: false);
4043
}
4144
}

src/EditorFeatures/Core/GoOrFind/AbstractGoOrFindNavigationService.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ protected virtual StreamingFindUsagesPresenterOptions GetStreamingPresenterOptio
8484
public bool IsAvailable([NotNullWhen(true)] Document? document)
8585
=> document?.GetLanguageService<TLanguageService>() != null;
8686

87-
public bool ExecuteCommand(Document document, int position)
87+
public bool ExecuteCommand(Document document, int position, bool allowInvalidPosition)
8888
{
8989
_threadingContext.ThrowIfNotOnUIThread();
9090
if (document is null)
@@ -100,14 +100,16 @@ public bool ExecuteCommand(Document document, int position)
100100

101101
// we're going to return immediately from ExecuteCommand and kick off our own async work to invoke the
102102
// operation. Once this returns, the editor will close the threaded wait dialog it created.
103-
_inProgressCommand = ExecuteCommandAsync(document, service, position, _cancellationTokenSource);
103+
_inProgressCommand = ExecuteCommandAsync(
104+
document, service, position, allowInvalidPosition, _cancellationTokenSource);
104105
return true;
105106
}
106107

107108
private async Task ExecuteCommandAsync(
108109
Document document,
109110
TLanguageService service,
110111
int position,
112+
bool allowInvalidPosition,
111113
CancellationTokenSource cancellationTokenSource)
112114
{
113115
// This is a fire-and-forget method (nothing guarantees observing it). As such, we have to handle cancellation
@@ -127,7 +129,8 @@ private async Task ExecuteCommandAsync(
127129
// any failures from it. Technically this should not be possible as it should be inside this same
128130
// try/catch. however this code wants to be very resilient to any prior mistakes infecting later operations.
129131
await _inProgressCommand.NoThrowAwaitable(captureContext: false);
130-
await ExecuteCommandWorkerAsync(document, service, position, cancellationTokenSource).ConfigureAwait(false);
132+
await ExecuteCommandWorkerAsync(
133+
document, service, position, allowInvalidPosition, cancellationTokenSource).ConfigureAwait(false);
131134
}
132135
catch (OperationCanceledException)
133136
{
@@ -141,6 +144,7 @@ private async Task ExecuteCommandWorkerAsync(
141144
Document document,
142145
TLanguageService service,
143146
int position,
147+
bool allowInvalidPosition,
144148
CancellationTokenSource cancellationTokenSource)
145149
{
146150
// Switch to the BG immediately so we can keep as much work off the UI thread.
@@ -161,7 +165,8 @@ private async Task ExecuteCommandWorkerAsync(
161165

162166
var cancellationToken = cancellationTokenSource.Token;
163167
var delayBeforeShowingResultsWindowTask = DelayAsync(cancellationToken);
164-
var findTask = FindResultsAsync(findContext, document, service, position, cancellationToken);
168+
var findTask = FindResultsAsync(
169+
findContext, document, service, position, allowInvalidPosition, cancellationToken);
165170

166171
var firstFinishedTask = await Task.WhenAny(delayBeforeShowingResultsWindowTask, findTask).ConfigureAwait(false);
167172
if (cancellationToken.IsCancellationRequested)
@@ -247,7 +252,12 @@ private async Task PresentResultsInStreamingPresenterAsync(
247252
}
248253

249254
private async Task FindResultsAsync(
250-
IFindUsagesContext findContext, Document document, TLanguageService service, int position, CancellationToken cancellationToken)
255+
IFindUsagesContext findContext,
256+
Document document,
257+
TLanguageService service,
258+
int position,
259+
bool allowInvalidPosition,
260+
CancellationToken cancellationToken)
251261
{
252262
// Ensure that we relinquish the thread so that the caller can proceed with their work.
253263
await TaskScheduler.Default.SwitchTo(alwaysYield: true);
@@ -266,6 +276,14 @@ await findContext.ReportMessageAsync(
266276
EditorFeaturesResources.The_results_may_be_incomplete_due_to_the_solution_still_loading_projects, NotificationSeverity.Information, cancellationToken).ConfigureAwait(false);
267277
}
268278

279+
// If we're allowing invalid positions (say from features that are passed stale positions),
280+
// then ensure the position is within the bounds of the document before proceeding.
281+
if (allowInvalidPosition)
282+
{
283+
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
284+
position = Math.Min(text.Length, position);
285+
}
286+
269287
// We were able to find the doc prior to loading the workspace (or else we would not have the service).
270288
// So we better be able to find it afterwards.
271289
await FindActionAsync(findContext, document, service, position, cancellationToken).ConfigureAwait(false);

src/EditorFeatures/Core/GoOrFind/IGoOrFindNavigationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ internal interface IGoOrFindNavigationService
1111
string DisplayName { get; }
1212

1313
bool IsAvailable([NotNullWhen(true)] Document? document);
14-
bool ExecuteCommand(Document document, int position);
14+
bool ExecuteCommand(Document document, int position, bool allowInvalidPosition);
1515
}

src/VisualStudio/Core/Def/Commands.vsct

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
<Group guid="guidRoslynGrpId" id="grpAnalyzerFolderContextMenu" priority="0x000">
2020
<Parent guid="guidRoslynGrpId" id="cmdidAnalyzerFolderContextMenu"/>
2121
</Group>
22+
23+
<Group guid="guidRoslynGrpId" id="grpSolutionExplorerSymbolItemContextMenu" priority="0x000">
24+
<Parent guid="guidRoslynGrpId" id="cmdidSolutionExplorerSymbolItemContextMenu"/>
25+
</Group>
2226

2327
<Group guid="guidRoslynGrpId" id="grpErrorListContextMenu" priority="0x0A01">
2428
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ERRORLIST"/>
@@ -377,6 +381,33 @@
377381
<LocCanonicalName>ResetVisualBasicInteractiveFromProject</LocCanonicalName>
378382
</Strings>
379383
</Button>
384+
385+
<!-- Solution Explorer Symbol Item commands -->
386+
387+
<Button guid="guidRoslynGrpId" id="cmdidSolutionExplorerSymbolItemGoToBase" priority="100" type="Button">
388+
<Parent guid="guidRoslynGrpId" id="grpSolutionExplorerSymbolItemContextMenu" />
389+
<Strings>
390+
<ButtonText>Go To Base</ButtonText>
391+
<CanonicalName>GoToBase</CanonicalName>
392+
<LocCanonicalName>GoToBase</LocCanonicalName>
393+
</Strings>
394+
</Button>
395+
<Button guid="guidRoslynGrpId" id="cmdidSolutionExplorerSymbolItemGoToImplementation" priority="200" type="Button">
396+
<Parent guid="guidRoslynGrpId" id="grpSolutionExplorerSymbolItemContextMenu" />
397+
<Strings>
398+
<ButtonText>Go To Implementation</ButtonText>
399+
<CanonicalName>GoToImplementation</CanonicalName>
400+
<LocCanonicalName>GoToImplementation</LocCanonicalName>
401+
</Strings>
402+
</Button>
403+
<Button guid="guidRoslynGrpId" id="cmdidSolutionExplorerSymbolItemFindAllReferences" priority="300" type="Button">
404+
<Parent guid="guidRoslynGrpId" id="grpSolutionExplorerSymbolItemContextMenu" />
405+
<Strings>
406+
<ButtonText>Find All References</ButtonText>
407+
<CanonicalName>FindAllReferences</CanonicalName>
408+
<LocCanonicalName>FindAllReferences</LocCanonicalName>
409+
</Strings>
410+
</Button>
380411

381412
<!-- Run code analysis commands -->
382413

@@ -476,7 +507,7 @@
476507
<CommandFlag>IconAndText</CommandFlag>
477508
<Strings>
478509
<ButtonText>Clear</ButtonText>
479-
<CommandName>CleearStackTraceExplorerCommandName</CommandName>
510+
<CommandName>ClearStackTraceExplorerCommandName</CommandName>
480511
<CanonicalName>ClearStackTraceExplorer</CanonicalName>
481512
<LocCanonicalName>ClearStackTraceExplorer</LocCanonicalName>
482513
</Strings>
@@ -557,7 +588,6 @@
557588
<LocCanonicalName>Analyzer</LocCanonicalName>
558589
</Strings>
559590
</Menu>
560-
561591
<Menu guid="guidRoslynGrpId" id="cmdidAnalyzerFolderContextMenu" priority="100" type="Context">
562592
<Parent guid="guidSHLMainMenu" id="IDG_VS_CTXT_SOLNEXPL_ALL" />
563593
<Strings>
@@ -622,6 +652,13 @@
622652
</Strings>
623653
</Menu>
624654

655+
<Menu guid="guidRoslynGrpId" id="cmdidSolutionExplorerSymbolItemContextMenu" type="Context">
656+
<Strings>
657+
<MenuText>Solution Explorer Symbol Tree</MenuText>
658+
<ButtonText>Solution Explorer Symbol Tree</ButtonText>
659+
</Strings>
660+
</Menu>
661+
625662
<!-- Document Outline toolbar -->
626663
<Menu guid="guidRoslynGrpId" id="cmdidDocumentOutlineToolbar" type="Toolbar">
627664
<CommandFlag>NotInTBList</CommandFlag>
@@ -774,14 +811,10 @@
774811
<IDSymbol name="grpErrorListDiagnosticSeverityItems" value="0x012a" />
775812

776813
<IDSymbol name="cmdidGoToImplementation" value="0x0200" />
777-
778-
<IDSymbol name="cmdidRunCodeAnalysisForProject" value="0x0201" />
779-
780-
<IDSymbol name="cmdidRemoveUnusedReferences" value="0x202" />
781-
782-
<IDSymbol name="cmdidshowValueTracking" value="0x0203" />
783-
784-
<IDSymbol name="cmdidSyncNamespaces" value="0x204" />
814+
<IDSymbol name="cmdidRunCodeAnalysisForProject" value="0x0201" />
815+
<IDSymbol name="cmdidRemoveUnusedReferences" value="0x0202" />
816+
<IDSymbol name="cmdidshowValueTracking" value="0x0203" />
817+
<IDSymbol name="cmdidSyncNamespaces" value="0x0204" />
785818

786819
<IDSymbol name="cmdidDocumentOutlineToolbar" value="0x300" />
787820
<IDSymbol name="cmdidDocumentOutlineExpandAll" value="0x311"/>
@@ -790,6 +823,12 @@
790823
<IDSymbol name="cmdidDocumentOutlineSortByOrder" value="0x314"/>
791824
<IDSymbol name="cmdidDocumentOutlineSortByType" value="0x315"/>
792825
<IDSymbol name="cmdidDocumentOutlineToolbarGroup" value="0x350" />
826+
827+
<IDSymbol name="grpSolutionExplorerSymbolItemContextMenu" value="0x0400" />
828+
<IDSymbol name="cmdidSolutionExplorerSymbolItemContextMenu" value="0x0401" />
829+
<IDSymbol name="cmdidSolutionExplorerSymbolItemGoToBase" value="0x0402" />
830+
<IDSymbol name="cmdidSolutionExplorerSymbolItemGoToImplementation" value="0x0403" />
831+
<IDSymbol name="cmdidSolutionExplorerSymbolItemFindAllReferences" value="0x0404" />
793832
</GuidSymbol>
794833

795834
<GuidSymbol name="guidCSharpInteractiveCommandSet" value="{1492db0a-85a2-4e43-bf0d-ce55b89a8cc6}">

src/VisualStudio/Core/Def/ID.RoslynCommands.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,10 @@ public static class RoslynCommands
4646
public const int DocumentOutlineSortByOrder = 0x314;
4747
public const int DocumentOutlineSortByType = 0x315;
4848
public const int DocumentOutlineToolbarGroup = 0x350;
49+
50+
public const int SolutionExplorerSymbolItemContextMenu = 0x401;
51+
public const int SolutionExplorerSymbolItemGoToBase = 0x402;
52+
public const int SolutionExplorerSymbolItemGoToImplementation = 0x403;
53+
public const int SolutionExplorerSymbolItemFindAllReferences = 0x404;
4954
}
5055
}

src/VisualStudio/Core/Def/LanguageService/AbstractPackage.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System;
66
using System.Threading;
77
using System.Threading.Tasks;
8-
using Microsoft.CodeAnalysis.Options;
98
using Microsoft.VisualStudio.ComponentModelHost;
109
using Microsoft.VisualStudio.Shell;
1110

src/VisualStudio/Core/Def/PackageRegistration.pkgdef

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[$RootKey$\Menus]
2-
"{6cf2e545-6109-4730-8883-cf43d7aec3e1}"=", Menus.ctmenu, 21"
2+
"{6cf2e545-6109-4730-8883-cf43d7aec3e1}"=", Menus.ctmenu, 22"
33

44
// [ProvideUIContextRule(
55
// Guids.EncCapableProjectExistsInWorkspaceUIContextString,

src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf

Lines changed: 42 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf

Lines changed: 42 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)