Skip to content

Commit 6da87ad

Browse files
committed
Automatically start workspace if explicitly opened and not running
1 parent 9ff3cb6 commit 6da87ad

File tree

5 files changed

+182
-140
lines changed

5 files changed

+182
-140
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
### Changed
66

77
- Always enable verbose (`-v`) flag when a log directory is configured (`coder.proxyLogDir`).
8-
- Automatically start a workspace if it is opened but not running.
8+
- Automatically start a workspace without prompting if it is explicitly opened but not running.
99

1010
### Added
1111

src/commands.ts

Lines changed: 124 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ export class Commands {
451451
throw new Error("You are not logged in");
452452
}
453453
if (item instanceof AgentTreeItem) {
454-
await openWorkspace(
454+
await this.openWorkspace(
455455
baseUrl,
456456
item.workspace,
457457
item.agent,
@@ -465,7 +465,13 @@ export class Commands {
465465
// User declined to pick an agent.
466466
return;
467467
}
468-
await openWorkspace(baseUrl, item.workspace, agent, undefined, true);
468+
await this.openWorkspace(
469+
baseUrl,
470+
item.workspace,
471+
agent,
472+
undefined,
473+
true,
474+
);
469475
} else {
470476
throw new Error("Unable to open unknown sidebar item");
471477
}
@@ -583,7 +589,7 @@ export class Commands {
583589
return;
584590
}
585591

586-
await openWorkspace(baseUrl, workspace, agent, folderPath, openRecent);
592+
await this.openWorkspace(baseUrl, workspace, agent, folderPath, openRecent);
587593
}
588594

589595
/**
@@ -605,15 +611,49 @@ export class Commands {
605611
throw new Error("You are not logged in");
606612
}
607613

608-
await openDevContainer(
614+
const remoteAuthority = toRemoteAuthority(
609615
baseUrl,
610616
workspaceOwner,
611617
workspaceName,
612618
workspaceAgent,
613-
devContainerName,
614-
devContainerFolder,
615-
localWorkspaceFolder,
616-
localConfigFile,
619+
);
620+
621+
const hostPath = localWorkspaceFolder ? localWorkspaceFolder : undefined;
622+
const configFile =
623+
hostPath && localConfigFile
624+
? {
625+
path: localConfigFile,
626+
scheme: "vscode-fileHost",
627+
}
628+
: undefined;
629+
const devContainer = Buffer.from(
630+
JSON.stringify({
631+
containerName: devContainerName,
632+
hostPath,
633+
configFile,
634+
localDocker: false,
635+
}),
636+
"utf-8",
637+
).toString("hex");
638+
639+
const type = localWorkspaceFolder ? "dev-container" : "attached-container";
640+
const devContainerAuthority = `${type}+${devContainer}@${remoteAuthority}`;
641+
642+
let newWindow = true;
643+
if (!vscode.workspace.workspaceFolders?.length) {
644+
newWindow = false;
645+
}
646+
647+
// Only set the memento if when opening a new folder
648+
await this.storage.setFirstConnect();
649+
await vscode.commands.executeCommand(
650+
"vscode.openFolder",
651+
vscode.Uri.from({
652+
scheme: "vscode-remote",
653+
authority: devContainerAuthority,
654+
path: devContainerFolder,
655+
}),
656+
newWindow,
617657
);
618658
}
619659

@@ -722,141 +762,89 @@ export class Commands {
722762
}
723763
return agents;
724764
}
725-
}
726-
727-
/**
728-
* Given a workspace and agent, build the host name, find a directory to open,
729-
* and pass both to the Remote SSH plugin in the form of a remote authority
730-
* URI.
731-
*
732-
* If provided, folderPath is always used, otherwise expanded_directory from
733-
* the agent is used.
734-
*/
735-
async function openWorkspace(
736-
baseUrl: string,
737-
workspace: Workspace,
738-
agent: WorkspaceAgent,
739-
folderPath: string | undefined,
740-
openRecent: boolean = false,
741-
) {
742-
const remoteAuthority = toRemoteAuthority(
743-
baseUrl,
744-
workspace.owner_name,
745-
workspace.name,
746-
agent.name,
747-
);
748-
749-
let newWindow = true;
750-
// Open in the existing window if no workspaces are open.
751-
if (!vscode.workspace.workspaceFolders?.length) {
752-
newWindow = false;
753-
}
754-
755-
if (!folderPath) {
756-
folderPath = agent.expanded_directory;
757-
}
758765

759-
// If the agent had no folder or we have been asked to open the most recent,
760-
// we can try to open a recently opened folder/workspace.
761-
if (!folderPath || openRecent) {
762-
const output: {
763-
workspaces: { folderUri: vscode.Uri; remoteAuthority: string }[];
764-
} = await vscode.commands.executeCommand("_workbench.getRecentlyOpened");
765-
const opened = output.workspaces.filter(
766-
// Remove recents that do not belong to this connection. The remote
767-
// authority maps to a workspace/agent combination (using the SSH host
768-
// name). There may also be some legacy connections that still may
769-
// reference a workspace without an agent name, which will be missed.
770-
(opened) => opened.folderUri?.authority === remoteAuthority,
766+
/**
767+
* Given a workspace and agent, build the host name, find a directory to open,
768+
* and pass both to the Remote SSH plugin in the form of a remote authority
769+
* URI.
770+
*
771+
* If provided, folderPath is always used, otherwise expanded_directory from
772+
* the agent is used.
773+
*/
774+
async openWorkspace(
775+
baseUrl: string,
776+
workspace: Workspace,
777+
agent: WorkspaceAgent,
778+
folderPath: string | undefined,
779+
openRecent: boolean = false,
780+
) {
781+
const remoteAuthority = toRemoteAuthority(
782+
baseUrl,
783+
workspace.owner_name,
784+
workspace.name,
785+
agent.name,
771786
);
772787

773-
// openRecent will always use the most recent. Otherwise, if there are
774-
// multiple we ask the user which to use.
775-
if (opened.length === 1 || (opened.length > 1 && openRecent)) {
776-
folderPath = opened[0].folderUri.path;
777-
} else if (opened.length > 1) {
778-
const items = opened.map((f) => f.folderUri.path);
779-
folderPath = await vscode.window.showQuickPick(items, {
780-
title: "Select a recently opened folder",
781-
});
782-
if (!folderPath) {
783-
// User aborted.
784-
return;
785-
}
788+
let newWindow = true;
789+
// Open in the existing window if no workspaces are open.
790+
if (!vscode.workspace.workspaceFolders?.length) {
791+
newWindow = false;
786792
}
787-
}
788793

789-
if (folderPath) {
790-
await vscode.commands.executeCommand(
791-
"vscode.openFolder",
792-
vscode.Uri.from({
793-
scheme: "vscode-remote",
794-
authority: remoteAuthority,
795-
path: folderPath,
796-
}),
797-
// Open this in a new window!
798-
newWindow,
799-
);
800-
return;
801-
}
794+
if (!folderPath) {
795+
folderPath = agent.expanded_directory;
796+
}
802797

803-
// This opens the workspace without an active folder opened.
804-
await vscode.commands.executeCommand("vscode.newWindow", {
805-
remoteAuthority: remoteAuthority,
806-
reuseWindow: !newWindow,
807-
});
808-
}
798+
// If the agent had no folder or we have been asked to open the most recent,
799+
// we can try to open a recently opened folder/workspace.
800+
if (!folderPath || openRecent) {
801+
const output: {
802+
workspaces: { folderUri: vscode.Uri; remoteAuthority: string }[];
803+
} = await vscode.commands.executeCommand("_workbench.getRecentlyOpened");
804+
const opened = output.workspaces.filter(
805+
// Remove recents that do not belong to this connection. The remote
806+
// authority maps to a workspace/agent combination (using the SSH host
807+
// name). There may also be some legacy connections that still may
808+
// reference a workspace without an agent name, which will be missed.
809+
(opened) => opened.folderUri?.authority === remoteAuthority,
810+
);
809811

810-
async function openDevContainer(
811-
baseUrl: string,
812-
workspaceOwner: string,
813-
workspaceName: string,
814-
workspaceAgent: string,
815-
devContainerName: string,
816-
devContainerFolder: string,
817-
localWorkspaceFolder: string = "",
818-
localConfigFile: string = "",
819-
) {
820-
const remoteAuthority = toRemoteAuthority(
821-
baseUrl,
822-
workspaceOwner,
823-
workspaceName,
824-
workspaceAgent,
825-
);
826-
827-
const hostPath = localWorkspaceFolder ? localWorkspaceFolder : undefined;
828-
const configFile =
829-
hostPath && localConfigFile
830-
? {
831-
path: localConfigFile,
832-
scheme: "vscode-fileHost",
812+
// openRecent will always use the most recent. Otherwise, if there are
813+
// multiple we ask the user which to use.
814+
if (opened.length === 1 || (opened.length > 1 && openRecent)) {
815+
folderPath = opened[0].folderUri.path;
816+
} else if (opened.length > 1) {
817+
const items = opened.map((f) => f.folderUri.path);
818+
folderPath = await vscode.window.showQuickPick(items, {
819+
title: "Select a recently opened folder",
820+
});
821+
if (!folderPath) {
822+
// User aborted.
823+
return;
833824
}
834-
: undefined;
835-
const devContainer = Buffer.from(
836-
JSON.stringify({
837-
containerName: devContainerName,
838-
hostPath,
839-
configFile,
840-
localDocker: false,
841-
}),
842-
"utf-8",
843-
).toString("hex");
844-
845-
const type = localWorkspaceFolder ? "dev-container" : "attached-container";
846-
const devContainerAuthority = `${type}+${devContainer}@${remoteAuthority}`;
847-
848-
let newWindow = true;
849-
if (!vscode.workspace.workspaceFolders?.length) {
850-
newWindow = false;
851-
}
825+
}
826+
}
852827

853-
await vscode.commands.executeCommand(
854-
"vscode.openFolder",
855-
vscode.Uri.from({
856-
scheme: "vscode-remote",
857-
authority: devContainerAuthority,
858-
path: devContainerFolder,
859-
}),
860-
newWindow,
861-
);
828+
// Only set the memento if when opening a new folder/window
829+
await this.storage.setFirstConnect();
830+
if (folderPath) {
831+
await vscode.commands.executeCommand(
832+
"vscode.openFolder",
833+
vscode.Uri.from({
834+
scheme: "vscode-remote",
835+
authority: remoteAuthority,
836+
path: folderPath,
837+
}),
838+
// Open this in a new window!
839+
newWindow,
840+
);
841+
return;
842+
}
843+
844+
// This opens the workspace without an active folder opened.
845+
await vscode.commands.executeCommand("vscode.newWindow", {
846+
remoteAuthority: remoteAuthority,
847+
reuseWindow: !newWindow,
848+
});
849+
}
862850
}

src/extension.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
5757
ctx.logUri,
5858
);
5959

60+
// Try to clear this flag ASAP then pass it around if needed
61+
const isFirstConnect = await storage.getAndClearFirstConnect();
62+
6063
// This client tracks the current login and will be used through the life of
6164
// the plugin to poll workspaces for the current login, as well as being used
6265
// in commands that operate on the current login.
@@ -309,7 +312,10 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
309312
ctx.extensionMode,
310313
);
311314
try {
312-
const details = await remote.setup(vscodeProposed.env.remoteAuthority);
315+
const details = await remote.setup(
316+
vscodeProposed.env.remoteAuthority,
317+
isFirstConnect,
318+
);
313319
if (details) {
314320
// Authenticate the plugin client which is used in the sidebar to display
315321
// workspaces belonging to this deployment.

0 commit comments

Comments
 (0)