Skip to content

Add CurrentFile SaveAs() support #1261

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 5 commits into from
Apr 18, 2018
Merged
Changes from all 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
66 changes: 46 additions & 20 deletions src/features/ExtensionCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/

import os = require("os");
import path = require("path");
import vscode = require("vscode");
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import { LanguageClient, NotificationType, Position, Range, RequestType } from "vscode-languageclient";
import { IFeature } from "../feature";

Expand Down Expand Up @@ -132,7 +133,7 @@ export const CloseFileRequestType =
"editor/closeFile");

export const SaveFileRequestType =
new RequestType<string, EditorOperationResponse, void, void>(
new RequestType<ISaveFileDetails, EditorOperationResponse, void, void>(
"editor/saveFile");

export const ShowErrorMessageRequestType =
Expand All @@ -151,6 +152,11 @@ export const SetStatusBarMessageRequestType =
new RequestType<IStatusBarMessageDetails, EditorOperationResponse, void, void>(
"editor/setStatusBarMessage");

export interface ISaveFileDetails {
filePath: string;
newPath?: string;
}

export interface IStatusBarMessageDetails {
message: string;
timeout?: number;
Expand Down Expand Up @@ -238,7 +244,7 @@ export class ExtensionCommandsFeature implements IFeature {

this.languageClient.onRequest(
SaveFileRequestType,
(filePath) => this.saveFile(filePath));
(saveFileDetails) => this.saveFile(saveFileDetails));

this.languageClient.onRequest(
ShowInformationMessageRequestType,
Expand Down Expand Up @@ -382,24 +388,44 @@ export class ExtensionCommandsFeature implements IFeature {
return promise;
}

private saveFile(filePath: string): Thenable<EditorOperationResponse> {
private async saveFile(saveFileDetails: ISaveFileDetails): Promise<EditorOperationResponse> {
Copy link
Member

Choose a reason for hiding this comment

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

Did you have to switch this from a Thenable to a Promise to use async/await?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah -- as in @SeeminglyScience's snippet. Thenable doesn't type check.

Copy link
Member

Choose a reason for hiding this comment

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

good to know!


let promise: Thenable<EditorOperationResponse>;
if (this.findTextDocument(this.normalizeFilePath(filePath))) {
promise =
vscode.workspace.openTextDocument(filePath)
.then((doc) => {
if (doc.isDirty) {
doc.save();
}
})
.then((_) => EditorOperationResponse.Completed);
} else {
promise = Promise.resolve(EditorOperationResponse.Completed);
// If the file to save can't be found, just complete the request
if (!this.findTextDocument(this.normalizeFilePath(saveFileDetails.filePath))) {
return EditorOperationResponse.Completed;
}

return promise;
}
// If no newFile is given, just save the current file
if (!saveFileDetails.newPath) {
const doc = await vscode.workspace.openTextDocument(saveFileDetails.filePath);
if (doc.isDirty) {
await doc.save();
}

return EditorOperationResponse.Completed;
}

// Otherwise we want to save as a new file

// First turn the path we were given into an absolute path
// Relative paths are interpreted as relative to the original file
const newFileAbsolutePath = path.isAbsolute(saveFileDetails.newPath) ?
saveFileDetails.newPath :
path.resolve(path.dirname(saveFileDetails.filePath), saveFileDetails.newPath);

// Retrieve the text out of the current document
const oldDocument = await vscode.workspace.openTextDocument(saveFileDetails.filePath);

// Write it to the new document path
fs.writeFileSync(newFileAbsolutePath, oldDocument.getText());

// Finally open the new document
const newFileUri = vscode.Uri.file(newFileAbsolutePath);
const newFile = await vscode.workspace.openTextDocument(newFileUri);
vscode.window.showTextDocument(newFile, { preview: true });
Copy link
Member

Choose a reason for hiding this comment

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

preview should be true by default. Were you seeing otherwise?

Copy link
Contributor Author

@rjmholt rjmholt Apr 17, 2018

Choose a reason for hiding this comment

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

No no, and actually I originally just took it out. But I couldn't find a reference to what the default is in the documentation and decided that we may as well make the expected behaviour explicit.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good!


return EditorOperationResponse.Completed;
}

private normalizeFilePath(filePath: string): string {
const platform = os.platform();
Expand Down