Skip to content

Fix Intellisense in debugger tool windows#24484

Merged
olegtk merged 10 commits intodev15.6.x-vs-depsfrom
dev/olegtk/FixIntellisenseInImmediate
Feb 1, 2018
Merged

Fix Intellisense in debugger tool windows#24484
olegtk merged 10 commits intodev15.6.x-vs-depsfrom
dev/olegtk/FixIntellisenseInImmediate

Conversation

@olegtk
Copy link
Contributor

@olegtk olegtk commented Jan 26, 2018

Ask Mode template

Customer scenario

When debugging a VB application, a customer opens Immediate window and types "?" to dump a value of a variable. Instead of showing a completion, "??" is written to the Immediate Window.

Bugs this fixes

https://devdiv.visualstudio.com/DevDiv/_workitems/edit/557166

Workarounds, if any

N/A

Risk

Low, the fix only affects DebuggerIntellisenseFilter class and follows the approach already used by VenusCommandFilter.

Performance impact

No perf impact is expected as the fix just restores execution of existing command handlers in this scenario.

Is this a regression from a previous update?

It's a regression from 15.6 Preview2 caused by migrating all Roslyn command handlers to the new editor commanding.

Root cause analysis

We missed this issue in partner manual testing stage because we didn't include debugger team into the list of affected partners. Also this scenario is only covered by CQ tests, which took long to run and analyze.
This PR adds 2 basic C# and VB integration tests to cover this scenario in earlier development stage.

How was the bug found?

CQ test failure.


Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/557166

DebuggerIntellisenseFilter, just like VenusCommandFilter routes commands to the legacy command handler service, which now is no-op for VB/C#. And so now (again, just like VenusCommandFilter) in order to execute command handlers migrated to the editor commanding it needs to hookup the new editor command handler service, configured to the correct text view and subject buffer.

@olegtk olegtk requested a review from a team as a code owner January 26, 2018 17:33
@olegtk olegtk self-assigned this Jan 26, 2018
@olegtk olegtk added this to the 15.6 milestone Jan 26, 2018
where TLanguageService : AbstractLanguageService<TPackage, TLanguageService>
{
private readonly AbstractLanguageService<TPackage, TLanguageService> _languageService;
protected readonly AbstractLanguageService<TPackage, TLanguageService> _languageService;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 If you need to make this protected, use a property instead:

protected AbstractLanguageService<TPackage, TLanguageService> LanguageService { get; }

var vsCommandHandlerServiceAdapter = vsCommandHandlerServiceAdapterFactory.Create(ConvertTextView(),
GetSubjectBufferContainingCaret(), // our override doesn't actually check the caret and always returns _context.Buffer
NextCommandTarget);
NextCommandTarget = vsCommandHandlerServiceAdapter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Why still have the previous SetNextFilter method writing to the same field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. There is a weird dependency between SetNextFilter() and SetContext()/SetCommandHandlers() here, but I found a way to unify them so that NextCommadTarget is set in only one place

// types escape, so treat SCROLLUP like CANCEL. It's actually a CANCEL.
case VSConstants.VSStd2KCmdID.SCROLLUP:
ExecuteCancel(subjectBuffer, contentType, executeNextCommandTarget);
ExecuteCancel(subjectBuffer, contentType, () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 It's not clear to me why only two of the four uses of executeNextCommandTarget changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these 2 handle one command but execute another (SCROLLUP -> Cancel and TYPECHAR -> ShowMemberList). executeNextCommandTarget captures the original handled command so we cannot use it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did it work before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously it didn't matter because both Cancel and ShowMemberList commands were pretty much guaranteed to be handled by Roslyn command handlers inside ICommandHandlerService (poorly named CurrentHandlers property) - executeNextCommandTarget was never called.

Now we have a chain of (ICommandHandlerService: legacy command handlers if any) -> (IEditorCommandHandlerService: migrated command handlers) and all Roslyn handlers are actually in the latter (former is kept for TS/F#). So properly passing executed command matters now.

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sharwell asks many wise questions.

internal void SetCommandHandlers(ITextBuffer buffer)
{
this.CurrentHandlers = _commandFactory.GetService(buffer);
// Chain in editor command handler service. It will execute all our command handlers migrated to the modern editor commanding
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline before this.

VisualStudio.ImmediateWindow.ShowImmediateWindow(clearAll: true);
VisualStudio.SendKeys.Send("?n");
VisualStudio.Workspace.WaitForAsyncOperations(FeatureAttribute.CompletionSet);
VisualStudio.SendKeys.Send("1", VirtualKey.Enter);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is typing out the 1, it means a lack of completion would still pass. Should it send a tab instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, let me try it. Is there a way to validate the completion is up in your integration tests without going deep into editor bits?
Btw, Apex can do that, it also fully supports debugger toolwindows :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a way to make these tests rely on completion by sending Tab as you suggested.

@@ -39,8 +39,8 @@ End Module
VisualStudio.ImmediateWindow.ShowImmediateWindow(clearAll: true);
VisualStudio.SendKeys.Send("?");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VB unlike C# shows completion on ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@olegtk ? is a special thing, since VB makes a distinction between expressions and statements in the immediate window.

@olegtk
Copy link
Contributor Author

olegtk commented Jan 27, 2018

@dotnet-bot retest windows_release_unit32_prtest please

private void SetNextFilterWorker()
{
// We have a new _originalNextCommandFilter or new _context, reset NextCommandTarget chain based on their values.
// The chain is formed like this:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate this comment greatly, thank you.

// -> IVsCommandHandlerServiceAdapter (our command handlers migrated to the modern editor commanding)
// -> original next command filter
var nextCommandFilter = _originalNextCommandFilter;
if (_context != null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit I don't quite get this check here....can we add a comment to explain it? Is this some thing where we create one of these prior to having the buffer, and that's what the later hookup is for?

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than a request for another comment, this looks good. Thank you for adding integration tests too!

@jasonmalinowski
Copy link
Member

@olegtk Just to check: do we even need this filter anymore? If it is doing some special stuff, does it need to be chaining to the legacy Roslyn ones now? I'm not sure if we have F# or TypeScript stuff sitting atop this?

(more asking just to know what code might be dead or nearly dead.)

…into dev/olegtk/FixIntellisenseInImmediate
@jinujoseph
Copy link
Contributor

@olegtk Feel free to merge once test validation from partners sign off.
Approved to merge via Link .

@olegtk
Copy link
Contributor Author

olegtk commented Jan 31, 2018

We still need this filter because it's doing some unusual command routing (Scrollup->Cancel, TypeChar->TypeChar+ShowMemberList) etc. It can probably be done via regular command handling though.
Chaining legacy ICommandHandlerService can be removed once TS/F# migrate (no idea if they use this, I kept it just because we are in Escrow).

@olegtk olegtk merged commit a5a1dd8 into dev15.6.x-vs-deps Feb 1, 2018
@davkean davkean deleted the dev/olegtk/FixIntellisenseInImmediate branch June 21, 2018 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants