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
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@
//

using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
using System;

namespace Microsoft.PowerShell.EditorServices.Protocol.LanguageServer
{
[Obsolete("This class is deprecated. Use ShowHelpRequest instead.")]
public class ShowOnlineHelpRequest
{
public static readonly
RequestType<string, object, object, object> Type =
RequestType<string, object, object, object>.Create("powerShell/showOnlineHelp");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a newline here?

public class ShowHelpRequest
{
public static readonly
RequestType<string, object, object, object> Type =
RequestType<string, object, object, object>.Create("powerShell/showHelp");
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to play Devil's advocate here:

Is the reason for the breaking change just that "showOnlineHelp" would be an inaccurate name? Or does possibly getting offline help make the change breaking too?

Just thinking that there are plenty of APIs where the message name doesn't quite mean what it used to because changing the message name is a bigger breaking change than changing what the message does.

It may be that we want to break the message compatibility anyway, but we do have other clients that might benefit from us not changing the name.

Anyway, just want to ask the question: "if we change the functionality but not the message name, is this still a breaking change?" with the followup "if the message name change is the breaking change, is it worth the breakage?"

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 a command in the command pallet and not a settings related change or something along those lines... I think if someone complains we can consider a patch that will re-ADD the old functionality.

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 think what @rjmholt is talking about is breaking on both sides with the change of the message as PSES isn't used exclusively by vscode-powershell. I'm not opposed to keeping the message name the old one (in fact I think it should be a matter of just backing out a single commit on both sides...)

Copy link
Contributor

Choose a reason for hiding this comment

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

That sounds reasonable!

Copy link
Member

Choose a reason for hiding this comment

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

I'm game 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh sure, now I need to first remove my big foot from my mouth and figure out how to rewrite the git history...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There we go, apparently it's a simple interactive rebase off of master 😀

Copy link
Contributor

Choose a reason for hiding this comment

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

Depending on how brave you feel:

Brave way that deletes history

git reset --hard HEAD~1

There's a safer way to do it without git revert that I can't find a good answer for.

It makes no difference to the repo, since it will all be squashed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the interactive rebase allowed me to delete the commits that changed the wording of the message (which is partly why I made them separate commits) while still preserving the super difficult minor bug fix commit at the end there.

}
}
44 changes: 34 additions & 10 deletions src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public void Start()
this.HandleDocumentRangeFormattingRequest);

this.messageHandlers.SetRequestHandler(ShowOnlineHelpRequest.Type, this.HandleShowOnlineHelpRequest);
this.messageHandlers.SetRequestHandler(ShowHelpRequest.Type, this.HandleShowHelpRequest);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add newlines around this line to keep the style consistent?

this.messageHandlers.SetRequestHandler(ExpandAliasRequest.Type, this.HandleExpandAliasRequest);

this.messageHandlers.SetRequestHandler(FindModuleRequest.Type, this.HandleFindModuleRequest);
Expand Down Expand Up @@ -231,21 +232,44 @@ await requestContext.SendResult(
});
}

protected async Task HandleShowOnlineHelpRequest(
protected async Task HandleShowHelpRequest(
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: newline between functions

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);

const string CheckHelpScript = @"
[CmdletBinding()]
param (
[String]$CommandName
)
try {
$null = Microsoft.PowerShell.Core\Get-Command $CommandName -ErrorAction Stop
} catch [System.Management.Automation.CommandNotFoundException] {
$PSCmdlet.ThrowTerminatingError($PSItem)
}
try {
$null = Microsoft.PowerShell.Core\Get-Help $CommandName -Online
} catch [System.Management.Automation.PSInvalidOperationException] {
Microsoft.PowerShell.Core\Get-Help $CommandName -Full
}";
if (string.IsNullOrEmpty(helpParams)) { helpParams = "Get-Help"; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a newline above this if


PSCommand checkHelpPSCommand = new PSCommand()
Copy link
Contributor

Choose a reason for hiding this comment

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

I was about to complain about the lack of var here, but technically the type here is the return type of the method. So all I feel is ambivalence.

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 used PSCommand due to all the other comments about being explicit about the variable type 😁

Copy link
Contributor

@rjmholt rjmholt Sep 6, 2018

Choose a reason for hiding this comment

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

Wholly agree. In general you wouldn't lose explicit variable type constraints with var when the constructor is on the RHS of the assignment (var x = new Banana();), but here it's more nuanced because of a sort of Builder pattern scenario...

.AddScript(CheckHelpScript, useLocalScope: true)
.AddArgument(helpParams);
await editorSession.PowerShellContext.ExecuteCommand<PSObject>(checkHelpPSCommand, sendOutputToHost: true);
Copy link
Contributor

Choose a reason for hiding this comment

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

I would add a newline above the first await statement

await requestContext.SendResult(null);
}
protected async Task HandleShowOnlineHelpRequest(
Copy link
Contributor

Choose a reason for hiding this comment

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

Definitely add a newline before this method definition here

string helpParams,
RequestContext<object> requestContext
)
{
PSCommand commandDeprecated = new PSCommand()
.AddCommand("Microsoft.PowerShell.Utility\\Write-Verbose")
.AddParameter("Message", ";powerShell/showOnlineHelp' has been deprecated. Use 'powerShell/showHelp' instead.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Typo here I think (from ; to ')

await editorSession.PowerShellContext.ExecuteCommand<PSObject>(commandDeprecated, sendOutputToHost: true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of (or in addition to) a PSIC warning, we could log a warning to the log file. I could go either way on this.

Copy link
Contributor

@rjmholt rjmholt Sep 18, 2018

Choose a reason for hiding this comment

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

👍 on log file Actually, users won't read the log file, and it won't be relevant when looking back through the logs. We should warn the user somehow.

The ideal would be to launch a popup. But that would be a lot for this PR. Perhaps instead we can leave it as a PSIC message and open an issue to make a popup?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a newline above this await

await this.HandleShowHelpRequest(helpParams, requestContext);
}

private async Task HandleSetPSSARulesRequest(
object param,
Expand Down