diff --git a/.gitattributes b/.gitattributes index acd2115566..2a922ee8df 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,9 @@ # Set the default behavior, in case people don't have core.autocrlf set. * text=auto +# Set svg to binary type, as SVG is unlikely to be editted by hand. Can be treated as checked in blob +*.svg binary + # .gitattributes in project root # npm now seems to be insisting on LF - see https://github.com/npm/npm/issues/17161 package.json text eol=lf diff --git a/media/PwSh.svg b/media/PwSh.svg new file mode 100644 index 0000000000..681704b769 --- /dev/null +++ b/media/PwSh.svg @@ -0,0 +1,4 @@ + + + + diff --git a/package.json b/package.json index 0104f56f5a..7c429a586e 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "onCommand:PowerShell.SpecifyScriptArgs", "onCommand:PowerShell.ShowSessionConsole", "onCommand:PowerShell.ShowSessionMenu", - "onCommand:PowerShell.RestartSession" + "onCommand:PowerShell.RestartSession", + "onView:PowerShellCommands" ], "dependencies": { "vscode": "~1.1.21", @@ -58,6 +59,23 @@ "test": "node ./node_modules/vscode/bin/test" }, "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "PowerShellCommandExplorer", + "title": "PowerShell Command Explorer", + "icon": "media/pwsh.svg" + } + ] + }, + "views": { + "PowerShellCommandExplorer": [ + { + "id": "PowerShellCommands", + "name": "PowerShell Commands" + } + ] + }, "keybindings": [ { "command": "PowerShell.ShowHelp", @@ -86,6 +104,20 @@ "title": "Expand Alias", "category": "PowerShell" }, + { + "command": "PowerShell.RefreshCommandsExplorer", + "title": "Refresh", + "icon": { + "light": "resources/light/refresh.svg", + "dark": "resources/dark/refresh.svg" + }, + "category": "PowerShell" + }, + { + "command": "PowerShell.InsertCommand", + "title": "Insert Command", + "category": "PowerShell" + }, { "command": "PowerShell.OnlineHelp", "title": "Get Online Help for Command (Deprecated)", @@ -174,6 +206,23 @@ "command": "PowerShell.ShowHelp", "group": "2_powershell" } + ], + "view/title": [ + { + "command": "PowerShell.RefreshCommandsExplorer", + "when": "view == PowerShellCommands", + "group": "navigation" + } + ], + "view/item/context": [ + { + "command": "PowerShell.ShowHelp", + "when": "view == PowerShellCommands" + }, + { + "command": "PowerShell.InsertCommand", + "when": "view == PowerShellCommands" + } ] }, "problemMatchers": [ @@ -602,4 +651,4 @@ ] }, "private": true -} +} \ No newline at end of file diff --git a/resources/dark/refresh.svg b/resources/dark/refresh.svg new file mode 100644 index 0000000000..d79fdaa4e8 --- /dev/null +++ b/resources/dark/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/refresh.svg b/resources/light/refresh.svg new file mode 100644 index 0000000000..e034574819 --- /dev/null +++ b/resources/light/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/features/GetCommands.ts b/src/features/GetCommands.ts new file mode 100644 index 0000000000..0821a65a2d --- /dev/null +++ b/src/features/GetCommands.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ +import * as vscode from "vscode"; +import { LanguageClient, RequestType } from "vscode-languageclient"; +import { IFeature } from "../feature"; +import { Logger } from "../logging"; + +interface ICommand { + name: string; + moduleName: string; + defaultParameterSet: string; + parameterSets: object; + parameters: object; +} + +/** + * RequestType sent over to PSES. + * Expects: ICommand to be returned + */ +export const GetCommandRequestType = new RequestType("powerShell/getCommand"); + +/** + * A PowerShell Command listing feature. Implements a treeview control. + */ +export class GetCommandsFeature implements IFeature { + private command: vscode.Disposable; + private languageClient: LanguageClient; + private commandsExplorerProvider: CommandsExplorerProvider; + + constructor(private log: Logger) { + this.command = vscode.commands.registerCommand("PowerShell.RefreshCommandsExplorer", + () => this.CommandExplorerRefresh()); + this.commandsExplorerProvider = new CommandsExplorerProvider(); + vscode.window.registerTreeDataProvider("PowerShellCommands", this.commandsExplorerProvider); + vscode.commands.registerCommand("PowerShell.InsertCommand", (item) => this.InsertCommand(item)); + } + + public dispose() { + this.command.dispose(); + } + + public setLanguageClient(languageclient: LanguageClient) { + this.languageClient = languageclient; + vscode.commands.executeCommand("PowerShell.RefreshCommandsExplorer"); + } + + private CommandExplorerRefresh() { + if (this.languageClient === undefined) { + this.log.writeAndShowError(`<${GetCommandsFeature.name}>: ` + + "Unable to instantiate; language client undefined."); + return; + } + this.languageClient.sendRequest(GetCommandRequestType, "").then((result) => { + this.commandsExplorerProvider.powerShellCommands = result.map(toCommand); + this.commandsExplorerProvider.refresh(); + }); + } + + private InsertCommand(item) { + const editor = vscode.window.activeTextEditor; + const sls = editor.selection.start; + const sle = editor.selection.end; + const range = new vscode.Range(sls.line, sls.character, sle.line, sle.character); + editor.edit((editBuilder) => { + editBuilder.replace(range, item.Name); + }); + } +} + +class CommandsExplorerProvider implements vscode.TreeDataProvider { + public readonly onDidChangeTreeData: vscode.Event; + public powerShellCommands: Command[]; + private didChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); + + constructor() { + this.onDidChangeTreeData = this.didChangeTreeData.event; + } + + public refresh(): void { + this.didChangeTreeData.fire(); + } + + public getTreeItem(element: Command): vscode.TreeItem { + return element; + } + + public getChildren(element?: Command): Thenable { + return Promise.resolve(this.powerShellCommands || []); + } +} + +function toCommand(command: ICommand): Command { + return new Command( + command.name, + command.moduleName, + command.defaultParameterSet, + command.parameterSets, + command.parameters, + ); +} + +class Command extends vscode.TreeItem { + constructor( + public readonly Name: string, + public readonly ModuleName: string, + public readonly defaultParameterSet: string, + public readonly ParameterSets: object, + public readonly Parameters: object, + public readonly collapsibleState = vscode.TreeItemCollapsibleState.None, + ) { + super(Name, collapsibleState); + } + + public getTreeItem(): vscode.TreeItem { + return { + label: this.label, + collapsibleState: this.collapsibleState, + }; + } + + public async getChildren(element?): Promise { + return []; + // Returning an empty array because we need to return something. + } + +} diff --git a/src/features/ShowHelp.ts b/src/features/ShowHelp.ts index 5e8660eb34..e61f74d0a5 100644 --- a/src/features/ShowHelp.ts +++ b/src/features/ShowHelp.ts @@ -16,20 +16,25 @@ export class ShowHelpFeature implements IFeature { private languageClient: LanguageClient; constructor(private log: Logger) { - this.command = vscode.commands.registerCommand("PowerShell.ShowHelp", () => { + this.command = vscode.commands.registerCommand("PowerShell.ShowHelp", (item?) => { if (this.languageClient === undefined) { this.log.writeAndShowError(`<${ShowHelpFeature.name}>: ` + "Unable to instantiate; language client undefined."); return; } + if (item === undefined) { - const editor = vscode.window.activeTextEditor; - const selection = editor.selection; - const doc = editor.document; - const cwr = doc.getWordRangeAtPosition(selection.active); - const text = doc.getText(cwr); + const editor = vscode.window.activeTextEditor; - this.languageClient.sendRequest(ShowHelpRequestType, text); + const selection = editor.selection; + const doc = editor.document; + const cwr = doc.getWordRangeAtPosition(selection.active); + const text = doc.getText(cwr); + + this.languageClient.sendRequest(ShowHelpRequestType, text); + } else { + this.languageClient.sendRequest(ShowHelpRequestType, item.Name); + } }); this.deprecatedCommand = vscode.commands.registerCommand("PowerShell.OnlineHelp", () => { diff --git a/src/main.ts b/src/main.ts index 86482a05af..9313f7d026 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,6 +21,7 @@ import { ExtensionCommandsFeature } from "./features/ExtensionCommands"; import { FindModuleFeature } from "./features/FindModule"; import { FoldingFeature } from "./features/Folding"; import { GenerateBugReportFeature } from "./features/GenerateBugReport"; +import { GetCommandsFeature } from "./features/GetCommands"; import { HelpCompletionFeature } from "./features/HelpCompletion"; import { NewFileOrProjectFeature } from "./features/NewFileOrProject"; import { OpenInISEFeature } from "./features/OpenInISE"; @@ -123,6 +124,7 @@ export function activate(context: vscode.ExtensionContext): void { new OpenInISEFeature(), new GenerateBugReportFeature(sessionManager), new ExpandAliasFeature(logger), + new GetCommandsFeature(logger), new ShowHelpFeature(logger), new FindModuleFeature(), new PesterTestsFeature(sessionManager),