Skip to content

Change Get-Help behavior to return local help when no online help available #721

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

Merged
merged 15 commits into from
Sep 21, 2018
28 changes: 19 additions & 9 deletions src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,15 +235,25 @@ protected async Task HandleShowOnlineHelpRequest(
string helpParams,
RequestContext<object> requestContext)
{
if (helpParams == null) { helpParams = "get-help"; }

var psCommand = new PSCommand();
psCommand.AddCommand("Get-Help");
psCommand.AddArgument(helpParams);
psCommand.AddParameter("Online");

await editorSession.PowerShellContext.ExecuteCommand<object>(psCommand);

if (helpParams == null) { helpParams = "Get-Help"; }
string script = @"
Copy link
Member

Choose a reason for hiding this comment

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

You should pull this script out to a static private property so it's not created every time the function is run.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've moved this to a static private property, not sure if positioning it at the top of the file is the best spot for it, or what the convention is for this type of scenario.

[CmdletBinding()]
param (
[String]$CommandName
)
Try {
Microsoft.PowerShell.Core\Get-Command $CommandName -ErrorAction Stop | Out-Null
} catch [System.Management.Automation.CommandNotFoundException] {
$PSCmdlet.ThrowTerminatingError($PSItem)
Copy link
Member

Choose a reason for hiding this comment

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

I think, based on your logic here, that this this ThrowTerminatingError is redundant if you already have ErrorAction Stop

@SeeminglyScience correct me if I'm wrong here.

Copy link
Member

Choose a reason for hiding this comment

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

in other words you might be able to ditch the try/catch all together.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like it with the try catch because without it looks like this:
image

and with it looks like this:
image

But I will go with whichever you and @SeeminglyScience want.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@tylerl0706 the benefit of using ThrowTerminatingError over letting the exception propagate is that it changes the "context" of the error from the callee(?) to the caller.

Here's a little function you can use to check it out

function Test-TerminatingError {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, Mandatory)]
        [ValidateSet('NormalThrow', 'ThrowTerminatingError')]
        [string] $ThrowType
    )
    end {
        if ($ThrowType -eq 'NormalThrow') {                j
            Get-Command DefinitelyDoesntExist -ErrorAction Stop
        }

        try {
            Get-Command DefinitelyDoesntExist -ErrorAction Stop
        } catch {
            $PSCmdlet.ThrowTerminatingError($PSItem)
        }
    }
}

If NormalThrow is specified, this is what is displayed

Get-Command : The term 'DefinitelyDoesntExist' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:11 char:13
+             Get-Command DefinitelyDoesntExist -ErrorAction Stop
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (DefinitelyDoesntExist:String) [Get-Command], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

It shows the line in the function/script itself that failed, which is implementation detail the user doesn't care about. Contrast that to this:

Test-TerminatingError : The term 'DefinitelyDoesntExist' is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
and try again.
At line:1 char:1
+ Test-TerminatingError ThrowTerminatingError
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (DefinitelyDoesntExist:String) [Test-TerminatingError], CommandNotFoundE
   xception
    + FullyQualifiedErrorId : CommandNotFoundException,Test-TerminatingError

It also lets you fully (well mostly) customize the displayed error by creating your own ErrorRecord

All that said, @corbob that is definitely not how I expected that to look... something in our host does not handle that right...

We should still stick with it, but we should definitely look into why that's doing that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@SeeminglyScience should we be opening an issue for "something in our host does not handle that right...
...
we should definitely look into why that's doing that." ?

}
try {
Microsoft.PowerShell.Core\Get-Help $CommandName -Online | Out-Null
} catch [System.Management.Automation.PSInvalidOperationException] {
Microsoft.PowerShell.Core\Get-Help $CommandName -Full
}";
PSCommand checkHelpScript = new PSCommand();
checkHelpScript.AddScript(script,true).AddArgument(helpParams);
await editorSession.PowerShellContext.ExecuteCommand<PSObject>(checkHelpScript, true);
await requestContext.SendResult(null);
}

Expand Down