Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Handle cwd relative to workspace and named folders
  • Loading branch information
andyleejordan committed Aug 9, 2023
commit c0594bda48d07db1765c1ef17c833f9a49fa874d
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@
"powershell.cwd": {
"type": "string",
"default": "",
"markdownDescription": "An explicit start path where the Extension Terminal will be launched. Both the PowerShell process's and the shell's location will be set to this directory. **Path must be fully resolved: variables are not supported!**"
"markdownDescription": "A path where the Extension Terminal will be launched. Both the PowerShell process's and the shell's location will be set to this directory. Does not support variables, but does support the use of '~' and paths relative to a single workspace. **For multi-root workspaces, use the name of the folder you wish to have as the cwd.**"
},
"powershell.scriptAnalysis.enable": {
"type": "boolean",
Expand Down
65 changes: 45 additions & 20 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ export async function getChosenWorkspace(logger: ILogger | undefined): Promise<v
};

chosenWorkspace = await vscode.window.showWorkspaceFolderPick(options);

logger?.writeVerbose(`User selected workspace: '${chosenWorkspace?.name}'`);
if (chosenWorkspace === undefined) {
chosenWorkspace = vscode.workspace.workspaceFolders[0];
}
}

// NOTE: We don't rely on checking if `chosenWorkspace` is undefined because
Expand All @@ -247,34 +251,55 @@ export async function getChosenWorkspace(logger: ILogger | undefined): Promise<v
}

export async function validateCwdSetting(logger: ILogger | undefined): Promise<string> {
let cwd: string | undefined = utils.stripQuotePair(
vscode.workspace.getConfiguration(utils.PowerShellLanguageId).get<string>("cwd"));

// Use the resolved cwd setting if it exists. We're checking truthiness
// because it could be an empty string, in which case we ignore it.
if (cwd) {
cwd = path.resolve(untildify(cwd));
if (await utils.checkIfDirectoryExists(cwd)) {
return cwd;
let cwd = utils.stripQuotePair(
vscode.workspace.getConfiguration(utils.PowerShellLanguageId).get<string>("cwd"))
?? "";

// Replace ~ with home directory.
cwd = untildify(cwd);

// Use the cwd setting if it's absolute and exists. We don't use or resolve
// relative paths here because it'll be relative to the Code process's cwd,
// which is not what the user is expecting.
if (path.isAbsolute(cwd) && await utils.checkIfDirectoryExists(cwd)) {
return cwd;
}

// If the cwd matches the name of a workspace folder, use it. Essentially
// "choose" a workspace folder based off the cwd path, and so set the state
// appropriately for `getChosenWorkspace`.
if (vscode.workspace.workspaceFolders) {
for (const workspaceFolder of vscode.workspace.workspaceFolders) {
// TODO: With some more work, we could support paths relative to a
// workspace folder name too.
if (cwd === workspaceFolder.name) {
hasChosen = true;
chosenWorkspace = workspaceFolder;
cwd = "";
}
}
}

// Otherwise get a cwd from the workspace, if possible.
const workspace = await getChosenWorkspace(logger);
cwd = workspace?.uri.fsPath;
if (workspace === undefined) {
logger?.writeVerbose("Workspace was undefined, using homedir!");
return os.homedir();
}

// Save the picked 'cwd' to the workspace settings.
if (cwd && await utils.checkIfDirectoryExists(cwd)) {
// TODO: Stop saving this to settings! Instead, save the picked
// workspace (or save this, but in a cache).
await changeSetting("cwd", cwd, undefined, logger);
const workspacePath = workspace.uri.fsPath;

// Use the chosen workspace's root to resolve the cwd.
const relativePath = path.join(workspacePath, cwd);
if (await utils.checkIfDirectoryExists(relativePath)) {
return relativePath;
}

// If there were no workspace folders, or somehow they don't exist, use
// the home directory.
if (!cwd || !await utils.checkIfDirectoryExists(cwd)) {
return os.homedir();
// Just use the workspace path.
if (await utils.checkIfDirectoryExists(workspacePath)) {
return workspacePath;
}

return cwd;
// If all else fails, use the home directory.
return os.homedir();
}
11 changes: 9 additions & 2 deletions test/core/settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,18 @@ describe("Settings E2E", function () {
assert.strictEqual(await validateCwdSetting(undefined), os.homedir());
});

it("Resolves relative paths", async function () {
it("Accepts relative paths", async function () {
// A different than default folder that definitely exists and is relative
const cwd = path.join("~", "somewhere", "..");
const expected = path.join(os.homedir(), "somewhere", "..");
await changeCwdSetting(cwd);
assert.strictEqual(await validateCwdSetting(undefined), os.homedir());
assert.strictEqual(await validateCwdSetting(undefined), expected);
});

it("Handles relative paths", async function () {
await changeCwdSetting("./BinaryModule");
const expected = path.join(workspace, "./BinaryModule");
assert.strictEqual(await validateCwdSetting(undefined), expected);
});
});
});