Skip to content

Commit 745b96d

Browse files
committed
Improve PowerShell session management, status reporting, and logging
This change introduces a pretty large refactoring of the existing extension code to improve the overall user experience. Here is a summary of the changes: - The PowerShell session is now restartable at any time while VS Code is running without restarting the whole VS Code window. This is exposed through the "Restart PowerShell Session" command. - A new status indicator has been added to the status bar which lets the user know when the language server is starting, running, or in an error state. - Logs for the extension are now written to an output channel in the UI allowing the user to show them at any time with the "Show PowerShell Extension Logs" command. - Any failure to load the PowerShell session will show an error message to the user and give them the opportunity to show the extension logs. - If the PowerShell process ends unexpectedly at any time, the user will be shown a prompt to restart the session. - Logs for each session are now written out to individual log folders instead of creating them all in the same folder. Resolves #281.
1 parent fd7eaba commit 745b96d

17 files changed

+1034
-539
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ out/
55
node_modules/
66
logs/
77
modules/*
8+
sessions/*
89
!modules/README.md
910
vscode-powershell.zip
1011
vscps-preview.zip
11-
*.vsix
12+
*.vsix
13+
npm-debug.log

.vscodeignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ bin/EditorServices.log
88
bin/DebugAdapter.log
99
bin/*.vshost.*
1010
logs/**
11-
11+
sessions/**

examples/.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
"cwd": "${file}"
1111
}
1212
]
13-
}
13+
}

package.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"publisher": "ms-vscode",
66
"description": "Develop PowerShell scripts in Visual Studio Code!",
77
"engines": {
8-
"vscode": "1.x.x"
8+
"vscode": "^1.7.0"
99
},
1010
"license": "SEE LICENSE IN LICENSE.txt",
1111
"homepage": "https://github.com/PowerShell/vscode-powershell/blob/master/README.md",
@@ -89,6 +89,21 @@
8989
"title": "Run selection",
9090
"category": "PowerShell"
9191
},
92+
{
93+
"command": "PowerShell.RestartSession",
94+
"title": "Restart PowerShell Session",
95+
"category": "PowerShell"
96+
},
97+
{
98+
"command": "PowerShell.ShowLogs",
99+
"title": "Show PowerShell Extension Logs",
100+
"category": "PowerShell"
101+
},
102+
{
103+
"command": "PowerShell.OpenLogFolder",
104+
"title": "Open PowerShell Extension Logs Folder",
105+
"category": "PowerShell"
106+
},
92107
{
93108
"command": "PowerShell.OpenInISE",
94109
"title": "Open current file in PowerShell ISE",

scripts/Start-EditorServices.ps1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ param(
5757
# Are we running in PowerShell 5 or later?
5858
$isPS5orLater = $PSVersionTable.PSVersion.Major -ge 5
5959

60+
# If PSReadline is present in the session, remove it so that runspace
61+
# management is easier
62+
if ((Get-Module PSReadline).Count -ne 0) {
63+
Remove-Module PSReadline
64+
}
65+
6066
# This variable will be assigned later to contain information about
6167
# what happened while attempting to launch the PowerShell Editor
6268
# Services host
@@ -161,6 +167,7 @@ else {
161167
$languageServicePort = Get-AvailablePort
162168
$debugServicePort = Get-AvailablePort
163169

170+
# Create the Editor Services host
164171
$editorServicesHost =
165172
Start-EditorServicesHost `
166173
-HostName $HostName `

src/debugAdapter.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
/*---------------------------------------------------------
2+
* Copyright (C) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------*/
4+
15
import fs = require('fs');
26
import path = require('path');
37
import net = require('net');
48
import utils = require('./utils');
5-
import logging = require('./logging');
9+
import { Logger } from './logging';
610

711
// NOTE: The purpose of this file is to serve as a bridge between
812
// VS Code's debug adapter client (which communicates via stdio) and
@@ -11,13 +15,12 @@ import logging = require('./logging');
1115
// relay between the two transports.
1216

1317
var logBasePath = path.resolve(__dirname, "../logs");
14-
utils.ensurePathExists(logBasePath);
1518

1619
var debugAdapterLogWriter =
1720
fs.createWriteStream(
1821
path.resolve(
1922
logBasePath,
20-
logging.getLogName("DebugAdapterClient")));
23+
"DebugAdapter.log"));
2124

2225
// Pause the stdin buffer until we're connected to the
2326
// debug server

src/feature.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*---------------------------------------------------------
2+
* Copyright (C) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------*/
4+
5+
import vscode = require('vscode');
6+
import { LanguageClient } from 'vscode-languageclient';
7+
export { LanguageClient } from 'vscode-languageclient';
8+
9+
export interface IFeature extends vscode.Disposable {
10+
setLanguageClient(languageclient: LanguageClient);
11+
dispose();
12+
}

src/features/Console.ts

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
/*---------------------------------------------------------
2+
* Copyright (C) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------*/
4+
15
import vscode = require('vscode');
6+
import { IFeature } from '../feature';
27
import { LanguageClient, RequestType, NotificationType } from 'vscode-languageclient';
38

49
export namespace EvaluateRequest {
@@ -138,44 +143,66 @@ function onInputEntered(responseText: string): ShowInputPromptResponseBody {
138143
}
139144
}
140145

141-
export function registerConsoleCommands(client: LanguageClient): void {
146+
export class ConsoleFeature implements IFeature {
147+
private command: vscode.Disposable;
148+
private languageClient: LanguageClient;
149+
private consoleChannel: vscode.OutputChannel;
150+
151+
constructor() {
152+
this.command =
153+
vscode.commands.registerCommand('PowerShell.RunSelection', () => {
154+
if (this.languageClient === undefined) {
155+
// TODO: Log error message
156+
return;
157+
}
158+
159+
var editor = vscode.window.activeTextEditor;
160+
var selectionRange: vscode.Range = undefined;
161+
162+
if (!editor.selection.isEmpty) {
163+
selectionRange =
164+
new vscode.Range(
165+
editor.selection.start,
166+
editor.selection.end);
167+
}
168+
else {
169+
selectionRange = editor.document.lineAt(editor.selection.start.line).range;
170+
}
171+
172+
this.languageClient.sendRequest(EvaluateRequest.type, {
173+
expression: editor.document.getText(selectionRange)
174+
});
175+
});
176+
177+
this.consoleChannel = vscode.window.createOutputChannel("PowerShell Output");
178+
}
142179

143-
vscode.commands.registerCommand('PowerShell.RunSelection', () => {
144-
var editor = vscode.window.activeTextEditor;
145-
var selectionRange: vscode.Range = undefined;
180+
public setLanguageClient(languageClient: LanguageClient) {
181+
this.languageClient = languageClient;
146182

147-
if (!editor.selection.isEmpty) {
148-
selectionRange =
149-
new vscode.Range(
150-
editor.selection.start,
151-
editor.selection.end);
152-
}
153-
else {
154-
selectionRange = editor.document.lineAt(editor.selection.start.line).range;
155-
}
183+
this.languageClient.onRequest(
184+
ShowChoicePromptRequest.type,
185+
promptDetails => showChoicePrompt(promptDetails, this.languageClient));
156186

157-
client.sendRequest(EvaluateRequest.type, {
158-
expression: editor.document.getText(selectionRange)
159-
});
160-
});
187+
this.languageClient.onRequest(
188+
ShowInputPromptRequest.type,
189+
promptDetails => showInputPrompt(promptDetails, this.languageClient));
161190

162-
var consoleChannel = vscode.window.createOutputChannel("PowerShell Output");
163-
client.onNotification(OutputNotification.type, (output) => {
164-
var outputEditorExist = vscode.window.visibleTextEditors.some((editor) => {
165-
return editor.document.languageId == 'Log'
166-
});
167-
if (!outputEditorExist)
168-
consoleChannel.show(vscode.ViewColumn.Three);
169-
consoleChannel.append(output.output);
170-
});
191+
this.languageClient.onNotification(OutputNotification.type, (output) => {
192+
var outputEditorExist = vscode.window.visibleTextEditors.some((editor) => {
193+
return editor.document.languageId == 'Log'
194+
});
171195

172-
var t: Thenable<ShowChoicePromptResponseBody>;
196+
if (!outputEditorExist) {
197+
this.consoleChannel.show(vscode.ViewColumn.Three);
198+
}
173199

174-
client.onRequest(
175-
ShowChoicePromptRequest.type,
176-
promptDetails => showChoicePrompt(promptDetails, client));
200+
this.consoleChannel.append(output.output);
201+
});
202+
}
177203

178-
client.onRequest(
179-
ShowInputPromptRequest.type,
180-
promptDetails => showInputPrompt(promptDetails, client));
204+
public dispose() {
205+
this.command.dispose();
206+
this.consoleChannel.dispose();
207+
}
181208
}

src/features/ExpandAlias.ts

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,59 @@
1+
/*---------------------------------------------------------
2+
* Copyright (C) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------*/
4+
15
import vscode = require('vscode');
2-
import { LanguageClient, RequestType, NotificationType } from 'vscode-languageclient';
36
import Window = vscode.window;
7+
import { IFeature } from '../feature';
8+
import { LanguageClient, RequestType, NotificationType } from 'vscode-languageclient';
49

510
export namespace ExpandAliasRequest {
611
export const type: RequestType<string, any, void> = { get method() { return 'powerShell/expandAlias'; } };
712
}
813

9-
export function registerExpandAliasCommand(client: LanguageClient): void {
10-
var disposable = vscode.commands.registerCommand('PowerShell.ExpandAlias', () => {
11-
12-
var editor = Window.activeTextEditor;
13-
var document = editor.document;
14-
var selection = editor.selection;
15-
var text, range;
16-
17-
var sls = selection.start;
18-
var sle = selection.end;
19-
20-
if (
21-
(sls.character === sle.character) &&
22-
(sls.line === sle.line)
23-
) {
24-
text = document.getText();
25-
range = new vscode.Range(0, 0, document.lineCount, text.length);
26-
} else {
27-
text = document.getText(selection);
28-
range = new vscode.Range(sls.line, sls.character, sle.line, sle.character);
29-
}
30-
31-
client.sendRequest(ExpandAliasRequest.type, text).then((result) => {
32-
editor.edit((editBuilder) => {
33-
editBuilder.replace(range, result);
14+
export class ExpandAliasFeature implements IFeature {
15+
private command: vscode.Disposable;
16+
private languageClient: LanguageClient;
17+
18+
constructor() {
19+
this.command = vscode.commands.registerCommand('PowerShell.ExpandAlias', () => {
20+
if (this.languageClient === undefined) {
21+
// TODO: Log error message
22+
return;
23+
}
24+
25+
var editor = Window.activeTextEditor;
26+
var document = editor.document;
27+
var selection = editor.selection;
28+
var text, range;
29+
30+
var sls = selection.start;
31+
var sle = selection.end;
32+
33+
if (
34+
(sls.character === sle.character) &&
35+
(sls.line === sle.line)
36+
) {
37+
text = document.getText();
38+
range = new vscode.Range(0, 0, document.lineCount, text.length);
39+
} else {
40+
text = document.getText(selection);
41+
range = new vscode.Range(sls.line, sls.character, sle.line, sle.character);
42+
}
43+
44+
this.languageClient.sendRequest(ExpandAliasRequest.type, text).then((result) => {
45+
editor.edit((editBuilder) => {
46+
editBuilder.replace(range, result);
47+
});
3448
});
3549
});
36-
});
50+
}
51+
52+
public setLanguageClient(languageclient: LanguageClient) {
53+
this.languageClient = languageclient;
54+
}
55+
56+
public dispose() {
57+
this.command.dispose();
58+
}
3759
}

0 commit comments

Comments
 (0)