-
Notifications
You must be signed in to change notification settings - Fork 234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix a lot of IntelliSense issues #1799
Fix a lot of IntelliSense issues #1799
Conversation
// If PsesCompletionHandler is not marked as serial, then DidChangeTextDocument | ||
// notifications will end up cancelling completion. So quickly typing `Get-` | ||
// would result in no completions. | ||
// | ||
// This also lets completion requests interrupt time consuming background tasks | ||
// like the references code lens. | ||
.WithHandler<PsesCompletionHandler>( | ||
new JsonRpcHandlerOptions() { RequestProcessType = RequestProcessType.Serial }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥳
/// <returns>An array of CodeLenses.</returns> | ||
CodeLens[] ProvideCodeLenses(ScriptFile scriptFile); | ||
CodeLens[] ProvideCodeLenses(ScriptFile scriptFile, CancellationToken cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥳
// This async method is pretty dense with synchronous code | ||
// so it's helpful to add some yields. | ||
await Task.Yield(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -35,7 +35,7 @@ internal abstract class SynchronousTask<TResult> : ISynchronousTask | |||
CancellationToken cancellationToken) | |||
{ | |||
Logger = logger; | |||
_taskCompletionSource = new TaskCompletionSource<TResult>(); | |||
_taskCompletionSource = new TaskCompletionSource<TResult>(TaskCreationOptions.RunContinuationsAsynchronously); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we comment exactly why we're doing this? (Like what did you hit that we have to set it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can kind of think of it like .ConfigureAwait(false)
for completion sources. I didn't necessarily need to add it here, it was just a troubleshooting step, but we probably should be adding it everywhere. Related blog post
I can add a comment here but maybe I should just update all the other instances as well? If we go that route would you still prefer a comment over each one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to do it in this PR, but thanks for the blog post. I'll make an issue for further investigation.
new PSCommand() | ||
.AddCommand("Microsoft.PowerShell.Core\\Get-Command") | ||
.AddParameter("ListImported", true) | ||
.AddParameter("CommandType", CommandTypes.Alias), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, makes sense.
CommandHelpers.AliasMap aliases = await CommandHelpers.GetAliasesAsync( | ||
_executionService, | ||
cancellationToken).ConfigureAwait(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥳 yay for things being cancellable!
|
||
// If the current runspace is not out of process, then we call TabExpansion2 so | ||
// that we have the ability to issue pipeline stop requests on cancellation. | ||
if (executionService is PsesInternalHost psesInternalHost |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof, I would happily remove the IExecutionService
interface as it makes us do things like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah either the sync task itself needs to reference IExecutionService
or we need to strip it out. Or maybe there should be another interface that has state or w/e.
Maybe we hold off on tackling that until we get a source generator that handles the interface definitions for us? 🤷
// If the current runspace is not out of process, then we call TabExpansion2 so | ||
// that we have the ability to issue pipeline stop requests on cancellation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥳
if (completionMatch.ResultType is CompletionResultType.Variable | ||
&& completionMatch.CompletionText.EndsWith(":")) | ||
{ | ||
isIncomplete = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work 🥳
This stops completion from being cancelled whenever a DidChangeTextDocument notification is sent. Also lets completion cancel some other expensive requests like code lens.
We were exiting SynchronousTask.ExecuteSynchronously early if the cancellation was already requested. This was not setting our tcs state correctly, causing the caller to just fall off without warning.
The use of `Runspace.SessionStateProxy` while the pipeline thread is busy (even if you are **on** the pipeline thread) results in an exception. This also allows us to cancel `GetAliasesAsync`.
- Cancellation tokens are now propagated to all code lens providers. - Provider code that was heavy in synchronous code has some cancellation checks and `Task.Yield` calls to help keep thread pool threads more flexible.
Adding space to completion triggers lets us automatically give completion results for parameter values. This also required building in some support for marking completion results as "Incomplete". This means that the client will not cache results when standard identifier characters are typed. Mainly, this solves the scenario where you type space, get file completion results, and then type `-`. You expect to then get parameter names, but without marking "Incomplete", it will instead filter the file results.
That way any completion results from custom argument completers can be cancelled if they take too long and the user keeps typing.
3f9f9c7
to
8da0b79
Compare
Changes:
(each section is it's own commit for easier review)
Mark completion request handler as
Serial
This stops completion from being cancelled whenever a
DidChangeTextDocument
notification is sent. So previously, if you typedGet-
very quickly, you'd get no results at all. It also lets completion cancel some other expensive requests like code lens.Note: the one not fantastic down side of this is it makes "missing" code lenses more likely. By missing I mean:
I have not yet figured out a way to tell VSCode to just try again next time it's able. Also we were already getting this sometimes, but this change does make it at least a bit more likely.
Fix tasks never completing if cancelled quickly
We were exiting
SynchronousTask.ExecuteSynchronously
early if the cancellation was already requested. This was not setting our tcs state correctly, causing the caller to just fall off without warning. This made some things likefinally
andusing
disposals never happen.Make alias discovery possible on idle
The use of
Runspace.SessionStateProxy
while the pipeline thread is busy (even if you are on the pipeline thread) results in an exception.This also allows us to cancel
GetAliasesAsync
. This was really the main reason I was in there, but I also remembered a report from @ninmonkey about an exception here so two birds one stone.Add space to completion trigger characters
Note: We should be on the look out for feedback about this change and let it sit in preview slightly longer than we'd normally like to. It's possible this may need to be opt in, but I think the entire intellisense experience is now optimized enough to that the behavior is ideal.
Adding space to completion triggers lets us automatically give completion results for parameter values. This also required building in some support for marking completion results as "Incomplete". This means that the client will not cache results when standard identifier characters are typed.
Mainly, this solves the scenario where you type space, get file completion results, and then type
-
. You expect to then get parameter names, but without marking "Incomplete", it will instead filter the file results.Also fixed a scenario where you type
$script:
and on typing the:
it would not update to available script scope variables.Make completion requests cancellable
That way any completion results from custom argument completers can be cancelled if they take too long and the user keeps typing.
TabExpansion2
is a callback-like function similar toprompt
, partially for customizing tab completion but also for providing a command to get completion results.In non-remote runspaces, we can also use it as a completion source that we can cancel by way of issuing a pipeline stop request.