private JsonObject createLaunch(File installDir, File projectDir,
			Map<String, String> classpathSourceMap, String externalModules) throws IOException {

		// Get the path of Utility.jar so we can put it on the classpath
		String utilityJarPath = classpathSourceMap.keySet()
				.stream()
				.filter(e -> e.endsWith("Utility.jar"))
				.findFirst()
				.orElseThrow();

		// Get JVM args from launch.properties by calling LaunchSupport
		List<String> args = new ArrayList<>();
		args.add(System.getProperty("java.home") + "/bin/java");
		args.add("-cp");
		args.add(new File(installDir, "support/LaunchSupport.jar").getPath());
		args.add("LaunchSupport");
		args.add(installDir.getPath());
		args.add("-vmArgs");
		ProcessBuilder pb = new ProcessBuilder(args);
		Process p = pb.start();
		List<String> vmArgs = IOUtils.readLines(p.getInputStream(), StandardCharsets.UTF_8);

		// Build launch json object
		JsonObject json = new JsonObject();
		json.addProperty("version", "0.2.0");
		JsonArray configurationsArray = new JsonArray();
		json.add("configurations", configurationsArray);

		// Ghidra launcher
		JsonObject ghidraConfigObject = new JsonObject();
		configurationsArray.add(ghidraConfigObject);
		ghidraConfigObject.addProperty("type", "java");
		ghidraConfigObject.addProperty("name", "Ghidra");
		ghidraConfigObject.addProperty("request", "launch");
		ghidraConfigObject.addProperty("mainClass", Ghidra.class.getName());
		ghidraConfigObject.addProperty("args", GhidraRun.class.getName());
		JsonArray classPathsArray = new JsonArray();
		ghidraConfigObject.add("classPaths", classPathsArray);
		classPathsArray.add(utilityJarPath);
		JsonArray vmArgsArray = new JsonArray();
		ghidraConfigObject.add("vmArgs", vmArgsArray);
		if (externalModules != null) {
			vmArgsArray.add("-Dghidra.external.modules=" + externalModules);
		}
		vmArgs.forEach(vmArgsArray::add);

		// PyGhidra launcher
		JsonObject pyghidraConfigObject = new JsonObject();
		configurationsArray.add(pyghidraConfigObject);
		pyghidraConfigObject.addProperty("type", "debugpy");
		pyghidraConfigObject.addProperty("name", "PyGhidra");
		pyghidraConfigObject.addProperty("request", "launch");
		pyghidraConfigObject.addProperty("module", "pyghidra.ghidra_launch");
		pyghidraConfigObject.addProperty("args", GhidraRun.class.getName());
		JsonArray argsArray = new JsonArray();
		pyghidraConfigObject.add("args", argsArray);
		argsArray.add("--install-dir");
		argsArray.add(installDir.getAbsolutePath());
		argsArray.add("-g");
		argsArray.add(GhidraRun.class.getName());
		JsonObject envObject = new JsonObject();
		pyghidraConfigObject.add("env", envObject);
		envObject.addProperty("PYGHIDRA_DEBUG", "1");

		// Ghidra Attach
		JsonObject ghidraAttachObject = new JsonObject();
		configurationsArray.add(ghidraAttachObject);
		ghidraAttachObject.addProperty("type", "java");
		ghidraAttachObject.addProperty("name", "Ghidra Attach");
		ghidraAttachObject.addProperty("request", "attach");
		ghidraAttachObject.addProperty("hostName", "localhost");
		ghidraAttachObject.addProperty("port", 18001);
		
		return json;
	}
Creates the VSCode launch json

@param installDir The Ghidra installation directory
@param projectDir The VSCode project directory
@param classpathSourceMap The classpath/source map (see {@link #getClasspathSourceMap()})
@param externalModules The Ghidra external modules to pass to Ghidra (could be null)
@return The VSCode launch json
@throws IOException if an IO-related error occurs
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/vscode/VSCodeIntegrationPlugin.java