217 lines · 6.1 KB · Text
RawDownload
#!/usr/bin/env node const HELP = `USAGE  zed-local  [options]  [zed args] SUMMARY  Runs 1-6 instances of Zed using a locally-running collaboration server.  Each instance of Zed will be signed in as a different user specified in  either \`.admins.json\` or \`.admins.default.json\`.   All arguments after the initial options will be passed through to the first  instance of Zed. This can be used to test SSH remoting along with collab, like  so:   $ script/zed-local -2 ssh://your-ssh-uri-here OPTIONS  --help            Print this help message  --release         Build Zed in release mode  -2, -3, -4, ...   Spawn multiple Zed instances, with their windows tiled.  --top             Arrange the Zed windows so they take up the top half of the screen.  --stable          Use stable Zed release installed on local machine for all instances (except for the first one).  --preview         Like --stable, but uses the locally-installed preview release instead.`.trim(); const { spawn, execSync, execFileSync } = require("child_process");const assert = require("assert"); let users;if (process.env.SEED_PATH) {  users = require(process.env.SEED_PATH).admins;} else {  users = require("../crates/collab/seed.default.json").admins;  try {    const defaultUsers = users;    const customUsers = require("../crates/collab/seed.json").admins;    assert(customUsers.length > 0);    users = customUsers.concat(      defaultUsers.filter((user) => !customUsers.includes(user)),    );  } catch (_) {}} const RESOLUTION_REGEX = /(\d+) x (\d+)/;const DIGIT_FLAG_REGEX = /^--?(\d+)$/; let instanceCount = 1;let isReleaseMode = false;let isTop = false;let othersOnStable = false;let othersOnPreview = false;let isStateful = false; const args = process.argv.slice(2);while (args.length > 0) {  const arg = args[0];   const digitMatch = arg.match(DIGIT_FLAG_REGEX);  if (digitMatch) {    instanceCount = parseInt(digitMatch[1]);  } else if (arg === "--release") {    isReleaseMode = true;  } else if (arg == "--stateful") {    isStateful = true;  } else if (arg === "--top") {    isTop = true;  } else if (arg === "--help") {    console.log(HELP);    process.exit(0);  } else if (arg === "--stable") {    othersOnStable = true;  } else if (arg === "--preview") {    othersOnPreview = true;  } else {    break;  }   args.shift();}const os = require("os");const platform = os.platform(); let screenWidth, screenHeight;const titleBarHeight = 24; if (platform === "darwin") {  // macOS  const displayInfo = JSON.parse(    execFileSync("system_profiler", ["SPDisplaysDataType", "-json"], {      encoding: "utf8",    }),  );  const mainDisplayResolution = displayInfo?.SPDisplaysDataType?.flatMap(    (display) => display?.spdisplays_ndrvs,  )    ?.find((entry) => entry?.spdisplays_main === "spdisplays_yes")    ?._spdisplays_resolution?.match(RESOLUTION_REGEX);  if (!mainDisplayResolution) {    throw new Error("Could not parse screen resolution");  }  screenWidth = parseInt(mainDisplayResolution[1]);  screenHeight = parseInt(mainDisplayResolution[2]) - titleBarHeight;} else if (platform === "linux") {  // Linux  try {    const xrandrOutput = execSync('xrandr | grep "\\*" | cut -d" " -f4', {      encoding: "utf8",    }).trim();    [screenWidth, screenHeight] = xrandrOutput.split("x").map(Number);  } catch (err) {    console.log(err);    throw new Error("Could not get screen resolution");  }} else if (platform === "win32") {  // windows  try {    const resolutionOutput = execSync(      `powershell -Command "& {Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Size}"`,      { encoding: "utf8" },    ).trim();    [screenWidth, screenHeight] = resolutionOutput.match(/\d+/g).map(Number);  } catch (err) {    console.log(err);    throw new Error("Could not get screen resolution on Windows");  }} if (platform !== "win32") {  screenHeight -= titleBarHeight;} if (isTop) {  screenHeight = Math.floor(screenHeight / 2);} // Determine the window size for each instancelet rows;let columns;switch (instanceCount) {  case 1:    [rows, columns] = [1, 1];    break;  case 2:    [rows, columns] = [1, 2];    break;  case 3:  case 4:    [rows, columns] = [2, 2];    break;  case 5:  case 6:    [rows, columns] = [2, 3];    break;} const instanceWidth = Math.floor(screenWidth / columns);const instanceHeight = Math.floor(screenHeight / rows); // If a user is specified, make sure it's first in the listconst user = process.env.ZED_IMPERSONATE;if (user) {  users = [user].concat(users.filter((u) => u !== user));} let buildArgs = ["build"];let zedBinary = "target/debug/zed";if (isReleaseMode) {  buildArgs.push("--release");  zedBinary = "target/release/zed";} try {  execFileSync("cargo", buildArgs, {    stdio: "inherit",  });} catch (e) {  process.exit(0);} setTimeout(() => {  for (let i = 0; i < instanceCount; i++) {    const row = Math.floor(i / columns);    const column = i % columns;    let position;    if (platform == "win32") {      position = [column * instanceWidth, row * instanceHeight].join(",");    } else {      position = [        column * instanceWidth,        row * instanceHeight + titleBarHeight,      ].join(",");    }    const size = [instanceWidth, instanceHeight].join(",");    let binaryPath = zedBinary;    if (i != 0 && othersOnStable) {      binaryPath = "/Applications/Zed.app/Contents/MacOS/zed";    } else if (i != 0 && othersOnPreview) {      binaryPath = "/Applications/Zed Preview.app/Contents/MacOS/zed";    }    spawn(binaryPath, i == 0 ? args : [], {      stdio: "inherit",      env: Object.assign({}, process.env, {        ZED_IMPERSONATE: users[i],        ZED_WINDOW_POSITION: position,        ZED_STATELESS: isStateful && i == 0 ? "" : "1",        ZED_ALWAYS_ACTIVE: "1",        ZED_SERVER_URL: "http://localhost:3000",        ZED_RPC_URL: "http://localhost:8080/rpc",        ZED_ADMIN_API_TOKEN: "internal-api-key-secret",        ZED_WINDOW_SIZE: size,        ZED_CLIENT_CHECKSUM_SEED: "development-checksum-seed",        RUST_LOG: process.env.RUST_LOG || "info",      }),    });  }}, 0.1);