Skip to content

Commit 566c8b2

Browse files
committed
Report errors from extension API commands
The response is now `Completed` or `Failed` and returned appropriately. `NewFile` now takes (optional) content and fills the new file with it (which is all the VS Code API can do). `OpenFile` doesn't throw a cryptic error in the terminal if the file isn't found. The status bar messages are now properly disposed.
1 parent 9939ef9 commit 566c8b2

File tree

1 file changed

+42
-30
lines changed

1 file changed

+42
-30
lines changed

src/features/ExtensionCommands.ts

+42-30
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ export const GetEditorContextRequestType =
6868
export interface IGetEditorContextRequestArguments {
6969
}
7070

71+
// NOTE: The server at least now expects this response, but it's not used in any
72+
// way. In the future we could actually communicate an error to the user.
7173
enum EditorOperationResponse {
72-
Unsupported = 0,
7374
Completed,
75+
Failed
7476
}
7577

7678
export const InsertTextRequestType =
@@ -148,6 +150,7 @@ interface IInvokeRegisteredEditorCommandParameter {
148150
export class ExtensionCommandsFeature extends LanguageClientConsumer {
149151
private commands: vscode.Disposable[];
150152
private handlers: vscode.Disposable[] = [];
153+
private statusBarMessages: vscode.Disposable[] = [];
151154
private extensionCommands: IExtensionCommand[] = [];
152155

153156
constructor(private logger: ILogger) {
@@ -216,9 +219,7 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
216219

217220
this.languageClient.onRequest(
218221
NewFileRequestType,
219-
// NOTE: The VS Code API does not support naming a file as it's
220-
// opened, only when it's saved. Hence the argument is not used.
221-
(_filePath) => this.newFile()),
222+
(_content) => this.newFile(_content)),
222223

223224
this.languageClient.onRequest(
224225
OpenFileRequestType,
@@ -267,6 +268,9 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
267268
for (const handler of this.handlers) {
268269
handler.dispose();
269270
}
271+
for (const statusBarMessage of this.statusBarMessages) {
272+
statusBarMessage.dispose();
273+
}
270274
}
271275

272276
private addExtensionCommand(command: IExtensionCommandAddedNotificationBody): void {
@@ -355,27 +359,35 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
355359
};
356360
}
357361

358-
private async newFile(): Promise<EditorOperationResponse> {
359-
const doc = await vscode.workspace.openTextDocument({ content: "" });
362+
private async newFile(content: string): Promise<EditorOperationResponse> {
363+
const doc = await vscode.workspace.openTextDocument(
364+
{ language: "powershell", content: content });
360365
await vscode.window.showTextDocument(doc);
361366
return EditorOperationResponse.Completed;
362367
}
363368

364369
private async openFile(openFileDetails: IOpenFileDetails): Promise<EditorOperationResponse> {
365370
const filePath = await this.resolveFilePathWithCwd(openFileDetails.filePath);
366-
const doc = await vscode.workspace.openTextDocument(filePath);
367-
await vscode.window.showTextDocument(doc, { preview: openFileDetails.preview });
371+
try {
372+
const doc = await vscode.workspace.openTextDocument(filePath);
373+
await vscode.window.showTextDocument(doc, { preview: openFileDetails.preview });
374+
} catch {
375+
void this.logger.writeAndShowWarning(`File to open not found: ${filePath}`);
376+
return EditorOperationResponse.Failed;
377+
}
368378
return EditorOperationResponse.Completed;
369379
}
370380

371381
private async closeFile(filePath: string): Promise<EditorOperationResponse> {
372382
filePath = await this.resolveFilePathWithCwd(filePath);
373-
const doc = vscode.workspace.textDocuments.find((x) => x.fileName === filePath);
383+
const doc = vscode.workspace.textDocuments.find((x) => x.uri.fsPath === filePath);
374384
if (doc != undefined && !doc.isClosed) {
375385
await vscode.window.showTextDocument(doc);
376386
await vscode.commands.executeCommand("workbench.action.closeActiveEditor");
387+
return EditorOperationResponse.Completed;
377388
}
378-
return EditorOperationResponse.Completed;
389+
void this.logger.writeAndShowWarning(`File to close not found or already closed: ${filePath}`);
390+
return EditorOperationResponse.Failed;
379391
}
380392

381393
/**
@@ -388,17 +400,17 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
388400
if (saveFileDetails.filePath.startsWith("untitled") || saveFileDetails.filePath.startsWith("file")) {
389401
currentFileUri = vscode.Uri.parse(saveFileDetails.filePath);
390402
} else {
391-
currentFileUri = vscode.Uri.file(saveFileDetails.filePath);
403+
const filePath = await this.resolveFilePathWithCwd(saveFileDetails.filePath);
404+
currentFileUri = vscode.Uri.file(filePath);
392405
}
393406

394-
// If the file to save can't be found, just complete the request
395-
const doc = vscode.workspace.textDocuments.find((x) => x.uri === currentFileUri);
407+
const doc = vscode.workspace.textDocuments.find((x) => x.uri.fsPath === currentFileUri.fsPath);
396408
if (doc === undefined) {
397-
void this.logger.writeAndShowError(`File to save not found: ${currentFileUri.fsPath}`);
398-
return EditorOperationResponse.Completed;
409+
void this.logger.writeAndShowWarning(`File to save not found: ${currentFileUri.fsPath}`);
410+
return EditorOperationResponse.Failed;
399411
}
400412

401-
let newFilePath = saveFileDetails.newPath;
413+
let newFilePath = saveFileDetails.newPath ?? undefined; // Otherwise it's null.
402414
if (currentFileUri.scheme === "file") {
403415
// If no newFile is given, just save the current file
404416
if (newFilePath === undefined) {
@@ -416,31 +428,29 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
416428
} else if (currentFileUri.scheme === "untitled") {
417429
// We need a new name to save an untitled file
418430
if (newFilePath === undefined) {
419-
void this.logger.writeAndShowError("Cannot save untitled file! Try SaveAs(\"path/to/file.ps1\") instead.");
420-
return EditorOperationResponse.Completed;
431+
void this.logger.writeAndShowWarning("Cannot save untitled file! Try SaveAs(\"path/to/file.ps1\") instead.");
432+
return EditorOperationResponse.Failed;
421433
}
422434

423435
newFilePath = await this.resolveFilePathWithCwd(newFilePath);
424436
} else {
425437
// Other URI schemes are not supported
426438
const msg = JSON.stringify(saveFileDetails, undefined, 2);
427-
void this.logger.writeAndShowError(
439+
void this.logger.writeAndShowWarning(
428440
`<${ExtensionCommandsFeature.name}>: Saving a document with scheme '${currentFileUri.scheme}' ` +
429441
`is currently unsupported. Message: '${msg}'`);
430-
return EditorOperationResponse.Completed;
442+
return EditorOperationResponse.Failed;
431443
}
432444

433-
await this.saveFileAs(doc, newFilePath);
434-
return EditorOperationResponse.Completed;
435-
445+
return await this.saveFileAs(doc, newFilePath);
436446
}
437447

438448
/**
439449
* Take a document available to vscode at the given URI and save it to the given absolute path
440450
* @param documentUri the URI of the vscode document to save
441451
* @param filePath the absolute path to save the document contents to
442452
*/
443-
private async saveFileAs(doc: vscode.TextDocument, filePath: string): Promise<void> {
453+
private async saveFileAs(doc: vscode.TextDocument, filePath: string): Promise<EditorOperationResponse> {
444454
// Write the old document's contents to the new document path
445455
const newFileUri = vscode.Uri.file(filePath);
446456
try {
@@ -450,12 +460,13 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
450460
} catch (err) {
451461
void this.logger.writeAndShowWarning(`<${ExtensionCommandsFeature.name}>: ` +
452462
`Unable to save file to path '${filePath}': ${err}`);
453-
return;
463+
return EditorOperationResponse.Failed;
454464
}
455465

456466
// Finally open the new document
457467
const newFile = await vscode.workspace.openTextDocument(newFileUri);
458468
await vscode.window.showTextDocument(newFile, { preview: true });
469+
return EditorOperationResponse.Completed;
459470
}
460471

461472
// Resolve file path against user's CWD setting
@@ -474,9 +485,9 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
474485
asCodePosition(details.selectionRange.start)!,
475486
asCodePosition(details.selectionRange.end)!),
476487
];
488+
return EditorOperationResponse.Completed;
477489
}
478-
479-
return EditorOperationResponse.Completed;
490+
return EditorOperationResponse.Failed;
480491
}
481492

482493
private showInformationMessage(message: string): EditorOperationResponse {
@@ -496,11 +507,12 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer {
496507

497508
private setStatusBarMessage(messageDetails: IStatusBarMessageDetails): EditorOperationResponse {
498509
if (messageDetails.timeout) {
499-
vscode.window.setStatusBarMessage(messageDetails.message, messageDetails.timeout);
510+
this.statusBarMessages.push(
511+
vscode.window.setStatusBarMessage(messageDetails.message, messageDetails.timeout));
500512
} else {
501-
vscode.window.setStatusBarMessage(messageDetails.message);
513+
this.statusBarMessages.push(
514+
vscode.window.setStatusBarMessage(messageDetails.message));
502515
}
503-
504516
return EditorOperationResponse.Completed;
505517
}
506518
}

0 commit comments

Comments
 (0)