Skip to content

Make opening in an existing instance work outside code-server #2099

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 10 commits into from
Oct 12, 2020
3 changes: 1 addition & 2 deletions ci/build/test-standalone-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ main() {
./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python
local installed_extensions
installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
if [[ $installed_extensions != *"info Using config file ~/.config/code-server/config.yaml
ms-python.python" ]]; then
if [[ $installed_extensions != "ms-python.python" ]]; then
echo "Unexpected output from listing extensions:"
echo "$installed_extensions"
exit 1
Expand Down
25 changes: 25 additions & 0 deletions ci/dev/vscode.patch
Original file line number Diff line number Diff line change
Expand Up @@ -3035,6 +3035,31 @@ index b3c89e51cfc25a53293a352a2a8ad50d5f26d595..e21abe4e13bc25a5b72f556bbfb61085
registerSingleton(IExtHostTerminalService, ExtHostTerminalService);
registerSingleton(IExtHostTunnelService, ExtHostTunnelService);
+registerSingleton(IExtHostNodeProxy, class extends NotImplementedProxy<IExtHostNodeProxy>(String(IExtHostNodeProxy)) { whenReady = Promise.resolve(); });
diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts
index 7cae126cc0f804273850933468690e0f9f10a5b8..08c2aa5cdae3f3d06bb08b7055dc7e7def260132 100644
--- a/src/vs/workbench/api/node/extHostCLIServer.ts
+++ b/src/vs/workbench/api/node/extHostCLIServer.ts
@@ -11,6 +11,8 @@ import { IWindowOpenable, IOpenWindowOptions } from 'vs/platform/windows/common/
import { URI } from 'vs/base/common/uri';
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { ILogService } from 'vs/platform/log/common/log';
+import { join } from 'vs/base/common/path';
+import { tmpdir } from 'os';

export interface OpenCommandPipeArgs {
type: 'open';
@@ -54,6 +56,11 @@ export class CLIServer {
private async setup(): Promise<string> {
this._ipcHandlePath = generateRandomPipeName();

+ // NOTE@coder: Write this out so we can get the most recent path.
+ fs.promises.writeFile(join(tmpdir(), "vscode-ipc"), this._ipcHandlePath).catch((error) => {
+ this.logService.error(error);
+ });
+
try {
this._server.listen(this.ipcHandlePath);
this._server.on('error', err => this.logService.error(err));
diff --git a/src/vs/workbench/api/worker/extHost.worker.services.ts b/src/vs/workbench/api/worker/extHost.worker.services.ts
index 3843fdec386edc09a1d361b63de892a04e0070ed..8aac4df527857e964798362a69f5591bef07c165 100644
--- a/src/vs/workbench/api/worker/extHost.worker.services.ts
Expand Down
89 changes: 67 additions & 22 deletions src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as os from "os"
import * as path from "path"
import { Args as VsArgs } from "../../lib/vscode/src/vs/server/ipc"
import { AuthType } from "./http"
import { generatePassword, humanPath, paths } from "./util"
import { canConnect, generatePassword, humanPath, paths } from "./util"

export class Optional<T> {
public constructor(public readonly value?: T) {}
Expand Down Expand Up @@ -152,12 +152,12 @@ const options: Options<Required<Args>> = {
"new-window": {
type: "boolean",
short: "n",
description: "Force to open a new window. (use with open-in)",
description: "Force to open a new window.",
},
"reuse-window": {
type: "boolean",
short: "r",
description: "Force to open a file or folder in an already opened window. (use with open-in)",
description: "Force to open a file or folder in an already opened window.",
},

locale: { type: "string" },
Expand Down Expand Up @@ -327,6 +327,21 @@ export const parse = (

logger.debug("parsed command line", field("args", args))

return args
}

export async function setDefaults(args: Args): Promise<Args> {
args = { ...args }

if (!args["user-data-dir"]) {
await copyOldMacOSDataDir()
args["user-data-dir"] = paths.data
}

if (!args["extensions-dir"]) {
args["extensions-dir"] = path.join(args["user-data-dir"], "extensions")
}

// --verbose takes priority over --log and --log takes priority over the
// environment variable.
if (args.verbose) {
Expand Down Expand Up @@ -369,21 +384,6 @@ export const parse = (
return args
}

export async function setDefaults(args: Args): Promise<Args> {
args = { ...args }

if (!args["user-data-dir"]) {
await copyOldMacOSDataDir()
args["user-data-dir"] = paths.data
}

if (!args["extensions-dir"]) {
args["extensions-dir"] = path.join(args["user-data-dir"], "extensions")
}

return args
}

async function defaultConfigFile(): Promise<string> {
return `bind-addr: 127.0.0.1:8080
auth: password
Expand All @@ -410,10 +410,6 @@ export async function readConfigFile(configPath?: string): Promise<Args> {
logger.info(`Wrote default config file to ${humanPath(configPath)}`)
}

if (!process.env.CODE_SERVER_PARENT_PID && !process.env.VSCODE_IPC_HOOK_CLI) {
logger.info(`Using config file ${humanPath(configPath)}`)
}

const configFile = await fs.readFile(configPath)
const config = yaml.safeLoad(configFile.toString(), {
filename: configPath,
Expand Down Expand Up @@ -496,3 +492,52 @@ async function copyOldMacOSDataDir(): Promise<void> {
await fs.copy(oldDataDir, paths.data)
}
}

export const shouldRunVsCodeCli = (args: Args): boolean => {
return !!args["list-extensions"] || !!args["install-extension"] || !!args["uninstall-extension"]
}

/**
* Determine if it looks like the user is trying to open a file or folder in an
* existing instance. The arguments here should be the arguments the user
* explicitly passed on the command line, not defaults or the configuration.
*/
export const shouldOpenInExistingInstance = async (args: Args): Promise<string | undefined> => {
// Always use the existing instance if we're running from VS Code's terminal.
if (process.env.VSCODE_IPC_HOOK_CLI) {
return process.env.VSCODE_IPC_HOOK_CLI
}

const readSocketPath = async (): Promise<string | undefined> => {
try {
return await fs.readFile(path.join(os.tmpdir(), "vscode-ipc"), "utf8")
} catch (error) {
if (error.code !== "ENOENT") {
throw error
}
}
return undefined
}

// If these flags are set then assume the user is trying to open in an
// existing instance since these flags have no effect otherwise.
const openInFlagCount = ["reuse-window", "new-window"].reduce((prev, cur) => {
return args[cur as keyof Args] ? prev + 1 : prev
}, 0)
if (openInFlagCount > 0) {
return readSocketPath()
}

// It's possible the user is trying to spawn another instance of code-server.
// Check if any unrelated flags are set (check against one because `_` always
// exists), that a file or directory was passed, and that the socket is
// active.
if (Object.keys(args).length === 1 && args._.length > 0) {
const socketPath = await readSocketPath()
if (socketPath && (await canConnect(socketPath))) {
return socketPath
}
}

return undefined
}
Loading