Skip to content

Instantly share code, notes, and snippets.

@aadishv
Created June 10, 2025 04:39
Show Gist options
  • Select an option

  • Save aadishv/4c8a0b81252b00b0837b23692a31a6b4 to your computer and use it in GitHub Desktop.

Select an option

Save aadishv/4c8a0b81252b00b0837b23692a31a6b4 to your computer and use it in GitHub Desktop.

Integrated Terminal Linux Commands on Windows

User

How does the integrated terminal allow Linux/UNIX commands to be run on windows machines? Look through the codebase and think before returning an answer, cite code snippets

Agent

Use Tool: list_directory (call_gDj2Ar9YlXv9ttWQmGCGeEd3)

{
  "path": "pros-vsc"
}

Tool Results: call_gDj2Ar9YlXv9ttWQmGCGeEd3

Folders:

pros-vsc/.github pros-vsc/.vscode pros-vsc/media pros-vsc/src

Files:

pros-vsc/.eslintignore pros-vsc/.eslintrc.json pros-vsc/.gitignore pros-vsc/.pre-commit-config.yaml pros-vsc/.vscodeignore pros-vsc/CHANGELOG.md pros-vsc/CONTRIBUTING.md pros-vsc/LICENSE.txt pros-vsc/README.md pros-vsc/azure-pipelines.yml pros-vsc/package-lock.json pros-vsc/package.json pros-vsc/tsconfig.json

Agent

Use Tool: grep (call_n2vGbgi8jJaFCkAkL3u6LolX)

{
  "regex": "createTerminal",
  "include_pattern": "pros-vsc/src"
}

Tool Results: call_n2vGbgi8jJaFCkAkL3u6LolX

Found 1 matches:

Matches in pros-vsc/src/workspace_utils.ts

const getProsTerminal › L211-215


  // Create a new terminal with the correct path, return it.
  return vscode.window.createTerminal({
    name: "PROS Terminal",
    env: process.env,

Agent

Use Tool: grep (call_1Z1uVU6qVZuy1CK4MRtUShRW)

{
  "regex": "shell",
  "include_pattern": "pros-vsc/src"
}

Tool Results: call_1Z1uVU6qVZuy1CK4MRtUShRW

No matches found

Agent

Use Tool: grep (call_CIQWETvQRcQWtzMBPi5BHUmK)

{
  "regex": "process\\.platform",
  "include_pattern": "pros-vsc/src"
}

Tool Results: call_CIQWETvQRcQWtzMBPi5BHUmK

Found 1 matches:

Matches in pros-vsc/src/one-click/install.ts

const getOperatingSystem › L28-36

export const getOperatingSystem = () => {
  if (process.platform === "win32") {
    return "windows";
  }
  if (process.platform === "darwin") {
    return "macos";
  }
  return "linux";
};

Agent

Use Tool: list_directory (call_TUo05GLsdO6o1VSlgvckWXuv)

{
  "path": "pros-vsc/.vscode"
}

Tool Results: call_TUo05GLsdO6o1VSlgvckWXuv

Files:

pros-vsc/.vscode/extensions.json pros-vsc/.vscode/launch.json pros-vsc/.vscode/prosDocs.json pros-vsc/.vscode/settings.json pros-vsc/.vscode/tasks.json

Agent

Use Tool: read_file (call_wiLngD2xzKO6LZL8ZXpeIiK1)

{
  "path": "pros-vsc/.vscode/settings.json",
  "start_line": 1,
  "end_line": 200
}

Tool Results: call_wiLngD2xzKO6LZL8ZXpeIiK1

// Place your settings in this file to overwrite default and user settings. { "files.exclude": { "out": false // set this to true to hide the "out" folder with the compiled JS files }, "search.exclude": { "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts "typescript.tsc.autoDetect": "off", "cmake.configureOnOpen": false }

Agent

Use Tool: read_file (call_Pr3WBgMuDwAwsbGoPl2sp8n4)

{
  "path": "pros-vsc/.vscode/tasks.json",
  "start_line": 1,
  "end_line": 200
}

Tool Results: call_Pr3WBgMuDwAwsbGoPl2sp8n4

// See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format { "version": "2.0.0", "tasks": [ { "type": "npm", "script": "watch", "problemMatcher": "$tsc-watch", "isBackground": true, "presentation": { "reveal": "never" }, "group": { "kind": "build", "isDefault": true } } ] }

Agent

Use Tool: grep (call_1swNgIdL7LEjY5MkBLEkzd0j)

{
  "regex": "shellPath",
  "include_pattern": "pros-vsc/src"
}

Tool Results: call_1swNgIdL7LEjY5MkBLEkzd0j

No matches found

Agent

Use Tool: read_file (call_00iZQs9mYzp9TYNkRMIc5Tqh)

{
  "path": "pros-vsc/src/workspace_utils.ts",
  "start_line": 1,
  "end_line": 300
}

Tool Results: call_00iZQs9mYzp9TYNkRMIc5Tqh

import * as vscode from "vscode"; import * as path from "path"; import * as fs from "fs"; import { promisify } from "util"; import { getOperatingSystem } from "./one-click/install"; import { getChildProcessProsToolchainPath } from "./one-click/path"; import { configurePaths } from "./one-click/install";

/**

  • This function searches a directory of the workspace for a file with the given name
  • @param filename This is the name of the file to search for (including extension)
  • @param dir This is the directory to search in. Ex. "src" or "include" or "src/chassis". "root" causes the entire workspace to be searched.
  • @param debug This is a boolean that determines whether or not to log all potential matches + other debug messages
  • @returns The Uri of the first matching file if any are found, null if directory or file not found */ export const findFile = async ( filename: string, dir: string, debug: boolean = false ): Promise<vscode.Uri | null> => { const debugMsg = "While searching for " + filename + " in " + dir + ": ";

// Return null if either string or dir is undefined or null if ( filename === undefined || dir === undefined || filename === null || dir === null ) { if (debug) { // Log message if in debug mode console.log(debugMsg + "invalid input of some kind! "); } return null; }

// Perform search operation if (dir === "root") { // Search entire workspace if dir is "root" var searchResults = await vscode.workspace.findFiles(filename); } else { // Search specified directory if dir is not "root". This is done by using glob patterns. // Ex. "/src//main.cpp" searches for "main.cpp" in any folder named "src" in the workspace, including all folders inside of all folders labeled "src" in the workspace. // NOTE: The use of vscode's joinPath is not necesary here, since everything is a web uri so regardless of user OS, it will be a standard forward slash for filepaths. var searchResults = await vscode.workspace.findFiles( "/" + dir + "//" + filename ); }

// vscode's findFiles function returns a thenable which operates as an array of URIs. Thus, we can use array functions on it: if (searchResults.length === 0) { // Return null if no files found if (debug) { // Log message if in debug mode console.log(debugMsg + "no matching files found!"); } return null; } else if (debug) { // >= 1 matching file found, in debug mode searchResults.forEach((path) => { // Log all matching files found if in debug mode console.log(debugMsg + "matching file found: " + path); }); }

// Double check file exists (for some reason vscode's findFiles function returns files that don't exist for users of the web version of vscode sometimes) // (According to Benjamin Davis anyways) try { await vscode.workspace.fs.stat(searchResults[0]); } catch (err) { return null; }

// Return first matching file found if any are found return searchResults[0]; };

/**

  • This function searches the workspace for all instances of a project.pros file. It then returns the folders containing those files.
  • It is used to offer the user a choice of which pros project to work on in the event there are multiple in the current workspace.
  • @returns An array of every folder which houses a project.pros file in the workspace. Returns an empty array if none found. */ export async function findProsProjectFolders(debug: boolean = false) { // Type is any for js reasons. Doesn't really matter, will end up being a string array. const debugMsg = "While searching for pros project folder names: "; var array: any = []; if ( vscode.workspace.workspaceFolders === undefined || vscode.workspace.workspaceFolders === null ) { // Return empty array if no workspace folders if (debug) { // Log message if in debug mode console.log(debugMsg + "no workspace folders found!"); } return array; }

if (debug) { // Log list of found folders in workspace if in debug mode console.log( debugMsg + " candidate folders found: " + vscode.workspace.workspaceFolders ); }

for (const workspace of vscode.workspace.workspaceFolders) { // Loop through each workspace folder and check if it contains a project.pros file in any of its subfolders (or at root level) const currentDir = workspace.uri; // uri to top workspace folder const folders = await vscode.workspace.fs.readDirectory(currentDir); // all subfolders, subfiles of top workspace folder for (const folder of folders) { // Loop through each subfolder and check if it contains a project.pros file var exists = true; // assume it exists until proven otherwise

  try {
    // By using VSCode's stat function (and the uri parsing functions), this code should work regardless
    // of if the workspace is using a physical file system or not.
    const workspaceUri = vscode.Uri.file(
      path.join(currentDir.fsPath, folder[0])
    ); // uri to subfolder
    const uriString = `${workspaceUri.scheme}:${
      workspaceUri.path
    }/${"project.pros"}`; // uri path to project.pros file in subfolder (candidate)
    const uri = vscode.Uri.parse(uriString);

    // Check if candidate path actually leads to a project.pros file
    await vscode.workspace.fs.stat(uri);
  } catch (e) {
    // If not, set exists to false
    console.error(e);
    exists = false;
  }
  if (exists) {
    // We have confirmed that the candidate path leads to a project.pros file. Add this folder to the array.
    array.push(folder);
  }
}

}

if (debug) { // Log list of found folders in workspace if in debug mode console.log(debugMsg + " final list of folders found: " + array); }

return array; // return array of folders }

/**

  • This function is a convinient wrapper for findFile. It searches the entire workspace for a project.pros file.
  • @returns A boolean indicating whether or not the current workspace contains a pros project */ export const workspaceContainsProsProject = async ( debug: boolean = false ): Promise => { return (await findFile("project.pros", "root", debug)) !== null; };

/**

  • This function is a convinient wrapper for findFile. It searches the entire workspace for a project.pros file.
  • @returns A vscode.Uri pointing to the directory containing the project.pros file, or null if no project.pros file found */ export const getProjectFileDir = async ( debug: boolean = false ): Promise<vscode.Uri | null> => { let fullUri = await findFile("project.pros", "root", debug); // get uri of project.pros file if (fullUri === null) { // return null if no project.pros file found return null; } return vscode.Uri.file(path.dirname(fullUri.fsPath)); // return uri of directory containing project.pros file };

/**

  • This function creates or gets a reference to an existing vscode terminal named "PROS Terminal".
  • It also configures the path of the terminal to include the pros-cli.
  • It also cleans up any duplicate terminals named "PROS Terminal" that may exist.
  • @param context The vscode extension context
  • @returns A reference to the PROS terminal */ export const getProsTerminal = async ( context: vscode.ExtensionContext ): Promise<vscode.Terminal> => { // First, check if one or more terminals labeled "PROS Terminal" already exist. const prosTerminals = vscode.window.terminals.filter( (t) => t.name === "PROS Terminal" ); // Get all terminals named "PROS Terminal"

if (prosTerminals.length > 1) { // Clean up duplicate terminals prosTerminals.slice(1).forEach((t) => t.dispose()); }

// If there is already a terminal named "PROS Terminal" and it has the correct path, return it. if (prosTerminals.length) { const options: Readonly<vscode.TerminalOptions> = prosTerminals[0].creationOptions; if (options?.env?.PATH?.includes("pros-cli")) { // Only keep the existing terminal if it has the correct path return prosTerminals[0]; } }

// If there is not already a terminal named "PROS Terminal" or it does not have the correct path, create a new one. await configurePaths(context); // Configure the paths (see install.ts) so that everything runs properly when you click a button

// Create a new terminal with the correct path, return it. return vscode.window.createTerminal({ name: "PROS Terminal", env: process.env, }); };

/**

  • This function allows the user to choose which pros project to work on in the event there are multiple in the current workspace.
  • It also warns the user if there is no pros project in the current workspace.
  • @returns Nothing */ export async function chooseProject() { // First, check if the current workspace exists correctly if ( vscode.workspace.workspaceFolders === undefined || vscode.workspace.workspaceFolders === null ) { return; // return if no workspace folders }

// Second, check if the current workspace contains a pros project var array = await findProsProjectFolders(); // get list of folders which contain pros projects // If no pros projects found, warn user and return if (array.length === 0) { vscode.window.showInformationMessage( "No PROS Projects found in current directory!" ); return; }

// Third, prompt user to choose which pros project to work on const targetOptions: vscode.QuickPickOptions = { placeHolder: array[0].name, title: "Select the PROS project to work on", ignoreFocusOut: true, }; var folderNames: Array<vscode.QuickPickItem> = []; for (const f of array) { folderNames.push({ label: f[0], description: "" }); } folderNames.push({ label: "PROS: Cancel Selection", description: "Do not open a PROS project", }); // Display the options to users const target = await vscode.window.showQuickPick(folderNames, targetOptions); if (target === undefined) { throw new Error(); } if (target.label === "PROS: Cancel Selection") { return; } //This will open the folder the user selects await vscode.commands.executeCommand( "vscode.openFolder", vscode.Uri.file( path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, target.label) ) ); }

/**

  • This function modifies the c_cpp_properties.json file which is used by the C/C++ extension to provide intellisense.
  • This allows it to "understand" pros.
  • @param dirpath the path to the c_cpp_properties.json file
  • @param json json object
  • @param os user's OS (for pathing) */ const modifyCCppJson = async ( dirpath: vscode.Uri, json: any, os: string, debug: boolean = false ) => { // First, check if json configurations setting contains include section, if not, add it let include = path.join(dirpath.fsPath, "include"); if (!json.configurations[0].includePath.includes(include)) { json.configurations[0].includePath.push(include); }

// Third, setup cStandard, cppStandard, and intelliSenseMode json.configurations[0].cStandard = "gnu11"; json.configurations[0].cppStandard = "gnu++20"; json.configurations[0].intelliSenseMode = "gcc-arm";

// Fourth, account for mac users with different framework filepath

Agent

Use Tool: read_file (call_xbg2HGSXM6Sr6RNaTP4VQh2P)

{
  "path": "pros-vsc/src/one-click/install.ts",
  "start_line": 1,
  "end_line": 300
}

Tool Results: call_xbg2HGSXM6Sr6RNaTP4VQh2P

import * as vscode from "vscode";

import * as path from "path"; import * as os from "os"; import { downloadextract, chmod } from "./download"; import { getCurrentVersion, getCurrentReleaseVersion, getToolchainVersion, } from "./installed"; import * as fs from "fs"; import { promisify } from "util"; import * as child_process from "child_process"; import * as semver from "semver"; import { getChildProcessPath, getIntegratedTerminalPaths, getChildProcessProsToolchainPath, } from "./path"; import { prosLogger } from "../extension"; import { BackgroundProgress } from "../logger"; import * as device from "../device"; //TOOLCHAIN and CLI_EXEC_PATH are exported and used for running commands. export var TOOLCHAIN: string; export var CLI_EXEC_PATH: string; export var PATH_SEP: string;

export const getOperatingSystem = () => { if (process.platform === "win32") { return "windows"; } if (process.platform === "darwin") { return "macos"; } return "linux"; };

export async function removeDirAsync(directory: string, begin: boolean) { // get all files in directory if (begin) { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: "Cleaning Directory", cancellable: false, }, async (progress, token) => { await removeDirAsync(directory, false); } ); } const files = await fs.promises.readdir(directory); if (files.length > 0) { // iterate through found files and directory for (const file of files) { if ((await fs.promises.lstat(path.join(directory, file))).isDirectory()) { // if the file is found to be a directory, // recursively call this function to remove subdirectory await removeDirAsync(path.join(directory, file), false); } else { //delete the file await fs.promises.unlink(path.join(directory, file)); } } } // delete the directory now that it is empty. await fs.promises.rmdir(directory, { recursive: true, maxRetries: 20 }); return true; }

export async function uninstall(context: vscode.ExtensionContext) { const globalPath = context.globalStorageUri; const title = "Are you sure you want to uninstall PROS?"; const labelResponse = await vscode.window.showInformationMessage( title, "Uninstall Now!", "Uninstall CLI Only", "No Thanks." ); if (labelResponse === "Uninstall Now!") { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: "Uninstalling PROS", cancellable: false, }, async () => { try { await vscode.workspace.fs.delete( vscode.Uri.joinPath(globalPath, "install"), { recursive: true } ); } catch (err) { console.error(err); } try { await vscode.workspace.fs.delete( vscode.Uri.joinPath(globalPath, "download"), { recursive: true } ); } catch (err) { console.error(err); } } ); vscode.window.showInformationMessage("PROS Uninstalled!"); } else if (labelResponse === "Uninstall CLI Only") { const cliName = pros-cli-${getOperatingSystem()}; await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: "Uninstalling PROS CLI", cancellable: false, }, async () => { await vscode.workspace.fs.delete( vscode.Uri.joinPath(context.globalStorageUri, "install", cliName), { recursive: true } ); } ); } }

async function getUrls( cliVersion: number, toolchainVersion: string, vexcomVersion: string ) { var cliArch = "lin-64bit"; var toolchainArch = "x86_64"; var vexcomArch = "linux-x64";

await prosLogger.log( "OneClick", Selecting proper download URLS for CLI and Toolchain ); var operatingSystem = getOperatingSystem(); if (operatingSystem === "windows") { await prosLogger.log("OneClick", Windows detected, using Windows URLS); // Set system, path seperator, and downloads to windows version cliArch = "win-64bit"; vexcomArch = "win32"; } else if (operatingSystem === "macos") { await prosLogger.log("OneClick", MacOS detected, using MacOS URLS); // Set system, path seperator, and downloads to windows version cliArch = "macos-64bit"; toolchainArch = os.arch() === "x64" ? "darwin-x86_64" : "darwin-arm64"; vexcomArch = "osx"; } else { await prosLogger.log("OneClick", Linux detected, using Linux URLS); } var downloadCli = https://github.com/purduesigbots/pros-cli/releases/download/${cliVersion}/pros_cli-${cliVersion}-${cliArch}.zip; var downloadVexcom = https://pros.cs.purdue.edu/v5/_static/releases/vexcom_${vexcomVersion}-${vexcomArch}.zip; if (operatingSystem === "windows") { var downloadToolchain = https://github.com/purduesigbots/toolchain/releases/download/${toolchainVersion}/pros-toolchain-windows-formatted.zip; } else { let toolchainSemver = semver.parse(toolchainVersion, { loose: true }); toolchainVersion = ${toolchainSemver?.major}.${toolchainSemver?.minor}.rel${toolchainSemver?.patch}; var downloadToolchain = https://developer.arm.com/-/media/Files/downloads/gnu/${toolchainVersion}/binrel/arm-gnu-toolchain-${toolchainVersion}-${toolchainArch}-arm-none-eabi.tar.xz; }

const customCli = vscode.workspace .getConfiguration("pros") .get("OneClick: CLI Download URL") ?? "default"; const customToolchain = vscode.workspace .getConfiguration("pros") .get("OneClick: Toolchain Download URL") ?? "default"; await prosLogger.log("OneClick", Checking for custom installation URLs); console.log(Custom URLS: ${customCli} | ${customToolchain}); if (customCli !== "default") { try { downloadCli = customCli === "default" ? downloadCli : customCli; await prosLogger.log( "OneClick", Using custom CLI download URL: ${downloadCli} ); } catch (e: any) { await prosLogger.log("OneClick", Invalid custom CLI URL: ${customCli}); console.log( "CLI Url specified in PROS extension settings was invalid. Using default instead" ); } }

if (customToolchain !== "default") { try { downloadToolchain = customToolchain === "default" ? downloadToolchain : customToolchain; await prosLogger.log( "OneClick", Using custom Toolchain download URL: ${downloadToolchain} ); } catch (e: any) { await prosLogger.log( "OneClick", Invalid custom Toolchain URL: ${customToolchain} ); console.log( "Toolchain Url specified in PROS extension settings was invalid. Using default instead" ); } }

return [downloadCli, downloadToolchain, downloadVexcom]; }

export async function install(context: vscode.ExtensionContext) { const preparingInstall = new BackgroundProgress( "Verifying Current PROS Installation", false, true );

await prosLogger.log( "OneClick", "Configuring Environment Variables for PROS" ); await configurePaths(context); await prosLogger.log("OneClick", "Fetching Operating System...."); const system = getOperatingSystem();

await prosLogger.log("OneClick", Operating System Detected: ${system});

await prosLogger.log("OneClick", "Fetching Latest CLI Version....");

let cliVersion, toolchainVersion; try { cliVersion = await getCurrentReleaseVersion( "https://api.github.com/repos/purduesigbots/pros-cli/releases/latest" ); toolchainVersion = await getCurrentReleaseVersion( "https://api.github.com/repos/purduesigbots/toolchain/releases/latest" ); await prosLogger.log("OneClick", CLI Version: ${cliVersion}); } catch (e: any) { await prosLogger.log("OneClick", "Failed to access version number"); console.log("Hit the rate limit, please try again after some time."); cliVersion = undefined; } let vexcomVersion = "1_0_0_23";

if (cliVersion === undefined || toolchainVersion === undefined) { preparingInstall.stop(); throw new Error("Failed to access version number"); }

// Get system type, path string separator, CLI download url, and toolchain download url. // Default variables are based on linux. await prosLogger.log( "OneClick", "Fetching CLI and Toolchain Download URLs...." ); let [downloadCli, downloadToolchain, downloadVexcom] = await getUrls( cliVersion, toolchainVersion, vexcomVersion ); await prosLogger.log("OneClick", CLI Download URL: ${downloadCli}); await prosLogger.log( "OneClick", Toolchain Download URL: ${downloadToolchain} ); await prosLogger.log("OneClick", Vexcom Download URL: ${downloadVexcom});

// Set the installed file names var cliName = pros-cli-${system}.zip; var vexcomName = vex-vexcom-${system}.zip; var toolchainName = pros-toolchain-${ system === "windows" ? ${system}.zip:${system}.tar.xz };

// Verify that the CLI and toolchain are working before prompting user to install. await prosLogger.log("OneClick", "Checking Status of CLI and Toolchain...."); // Check if CLI is working, up to date and installed with OneClick let [cliExecPath, toolchainExecPath] = getIntegratedTerminalPaths(context); const addQuotes = system === "macos" && !os.cpus()[0].model.includes("Apple M"); let [currentCliVersion, isOneClickInstall] = await getCurrentVersion( path.join( ${addQuotes ? ": ""}${cliExecPath}${addQuotes ?" : ""}, "pros" ) ); let [currentToolchainVersion, isToolchainOneClickInstall] = await getToolchainVersion( path.join( ${addQuotes ? ": ""}${toolchainExecPath}${addQuotes ?" : ""}, "bin", "arm-none-eabi-g++" ) ); const cliWorking = currentCliVersion !== "0.0.0"; const toolchainWorking = currentToolchainVersion !== "0.0.0"; const vexcomWorking = await verifyVexcom();

//log the result of cli and toolchain working await prosLogger.log(

Agent

Use Tool: grep (call_jWCRoNjqT7KZLzZqJDx03Km8)

{
  "regex": "bash",
  "include_pattern": "pros-vsc/src"
}

Tool Results: call_jWCRoNjqT7KZLzZqJDx03Km8

No matches found

Agent

Use Tool: read_file (call_txIeXRcr1XJgdUFoxI1N8dBk)

{
  "path": "pros-vsc/src/one-click/path.ts",
  "start_line": 1,
  "end_line": 300
}

Tool Results: call_txIeXRcr1XJgdUFoxI1N8dBk

import * as path from "path"; import * as os from "os"; import * as vscode from "vscode"; import { getOperatingSystem } from "./install";

// Returns the path to the PROS CLI and PROS toolchain. // These paths should only be used in the integrated terminal, for some unknown // reason the spaces in the paths need to be escaped differently when running // outside the integrated terminal. export const getIntegratedTerminalPaths = ( context: vscode.ExtensionContext ): [string, string, string] => { const globalPath = context.globalStorageUri.fsPath; const system = getOperatingSystem();

// path to cli let cliExecPath = ${path.join(globalPath, "install", pros-cli-${system})};

// path to toolchain let toolchainPath = path.join( globalPath, "install", pros-toolchain-${ system === "windows" ? path.join("windows", "usr") : system } );

let vexcomPath = path.join(globalPath, "install", vex-vexcom-${system});

if (system === "macos" && !os.cpus()[0].model.includes("Apple M")) { // Escape spaces in paths on Intel Mac cliExecPath = cliExecPath.replace(/(\s+)/g, "\$1"); toolchainPath = toolchainPath.replace(/(\s+)/g, "\$1"); vexcomPath = vexcomPath.replace(/(\s+)/g, "\$1"); }

return [cliExecPath, toolchainPath, vexcomPath]; };

// Returns the path to the PROS CLI. // This path should only be used in child_process.exec calls, not the // integrated terminal. export const getChildProcessPath = (): string | undefined => { let path = process.env["PATH"]; if (getOperatingSystem() === "macos") { path = "${path?.replace(/\\/g, "")}"; } return path; };

// Returns the path to the PROS Toolchain. // This path should only be used in child_process.exec calls, not the // integrated terminal. export const getChildProcessProsToolchainPath = (): string | undefined => { let toolchainPath = process.env["PROS_TOOLCHAIN"]; if (getOperatingSystem() === "macos") { toolchainPath = ${toolchainPath?.replace(/\\/g, "")}; } return toolchainPath; };

Agent

Use Tool: read_file (call_p58YoBdmqkRGH614HgZPck9M)

{
  "path": "pros-vsc/package.json",
  "start_line": 1,
  "end_line": 200
}

Tool Results: call_p58YoBdmqkRGH614HgZPck9M

{ "name": "pros", "displayName": "PROS", "publisher": "sigbots", "description": "PROS Extension that allows for C/C++ Development for VEX V5 and VEX Cortex", "author": { "name": "Purdue ACM SIGBOTS" }, "license": "SEE LICENSE IN LICENSE.txt", "bugs": { "url": "https://github.com/purduesigbots/pros-vsc/issues", "email": "pros_development@cs.purdue.edu" }, "repository": { "type": "git", "url": "https://github.com/purduesigbots/pros-vsc.git" }, "homepage": "http://pros.cs.purdue.edu", "keywords": [ "vex", "v5", "pros", "education", "outreach", "robotics", "vrc", "cortex", "code", "autonomous", "opcontrol" ], "icon": "media/pros-tux-white.png", "galleryBanner": { "color": "#D6B872", "theme": "dark" }, "version": "0.8.2", "engines": { "vscode": "^1.82.0" }, "categories": [ "Other" ], "activationEvents": [ "workspaceContains:**/project.pros", "onCommand:pros.new", "onCommand:pros.welcome", "onCommand:pros.build&upload", "onView:prosTreeview", "onCommand:pros.selectProject" ], "main": "./out/extension.js", "contributes": { "viewsContainers": { "activitybar": [ { "id": "pros-view-container", "title": "PROS", "icon": "media/pros-tux-white.png" } ] }, "views": { "pros-view-container": [ { "id": "prosTreeview", "name": "PROS", "icon": "media/pros-tux-white.png", "contextualTitle": "PROS" }, { "when": "pros.betaFeaturesEnabled", "id": "pros.brainView", "name": "Brain View", "type": "webview", "contextualTitle": "Brain View" } ] }, "icons": { "pros-v5-brain": { "description": "V5 Brain", "default": { "fontPath": "media/vexicon.woff", "fontCharacter": "\E00C" } }, "pros-v5-controller": { "description": "V5 Controller", "default": { "fontPath": "media/vexicon.woff", "fontCharacter": "\E00D" } }, "pros-v5-unknown": { "description": "Unknown V5 Device", "default": { "fontPath": "media/vexicon.woff", "fontCharacter": "\E00A" } } }, "commands": [ { "command": "pros.build&upload", "title": "Build & Upload", "icon": { "light": "media/pros-tux-black.png", "dark": "media/pros-tux-white.png" } }, { "command": "pros.upload", "title": "PROS: Upload" }, { "command": "pros.build", "title": "PROS: Build" }, { "command": "pros.run", "title": "PROS: Run", "icon": { "light": "media/run-tux-black.png", "dark": "media/run-tux-white.png" } }, { "command": "pros.stop", "title": "PROS: Stop", "icon": { "light": "media/stop-tux-black.png", "dark": "media/stop-tux-white.png" } }, { "command": "pros.clean", "title": "PROS: Clean" }, { "command": "pros.terminal", "title": "PROS: Brain Terminal" }, { "command": "pros.showterminal", "title": "PROS: Integrated Terminal" }, { "command": "pros.batterymedic", "title": "PROS: Run Battery Medic" }, { "command": "pros.capture", "title": "PROS: Screenshot V5 Brain" }, { "command": "pros.upgrade", "title": "PROS: Upgrade Project" }, { "command": "pros.new", "title": "PROS: Create New PROS Project" }, { "command": "pros.infoProject", "title": "PROS: Project Information" }, { "command": "pros.resetConductor", "title": "PROS: Reset Conductor" }, { "command": "pros.welcome", "title": "PROS: Welcome" }, { "command": "pros.install", "title": "PROS: Install PROS" }, { "command": "pros.uninstall", "title": "PROS: Uninstall PROS" }, { "command": "pros.verify", "title": "PROS: Verify PROS Installation" }, { "command": "pros.selectProject", "title": "PROS: Select PROS Project" }, { "command": "pros.installVision", "title": "PROS: Install PROS Vision" }, { "command": "pros.uninstallVision", "title": "PROS: Uninstall PROS Vision" }, {

Agent

Use Tool: grep (call_OTGYeZ4a0BhRfApkxSMdFL2P)

{
  "regex": "configurePaths",
  "include_pattern": "pros-vsc/src"
}

Tool Results: call_OTGYeZ4a0BhRfApkxSMdFL2P

Found 8 matches:

Matches in pros-vsc/src/extension.ts

L36-44

import {
  install,
  configurePaths,
  uninstall,
  cleanup,
  installVision,
  uninstallVision,
  getOperatingSystem,
} from "./one-click/install";

async function activate( ) › L151-155


  // Sets up paths for integrated terminal (context is the vscode extension context)
  await configurePaths(context);

  // If we are in a pros project, set the variable which tracks that to true and set everything up

Matches in pros-vsc/src/one-click/install.ts

async function install( ) › L219-223

    "Configuring Environment Variables for PROS"
  );
  await configurePaths(context);
  await prosLogger.log("OneClick", "Fetching Operating System....");
  const system = getOperatingSystem();

async function cleanup( ) › L606-610

        await chmod(globalPath.fsPath, system);
        await prosLogger.log("OneClick", `Configuring environment variables`);
        await configurePaths(context).catch((e) => {
          prosLogger.log("OneClick", e, "ERROR");
        });

async function configurePaths( ) › L639-649

export async function configurePaths(
  context: vscode.ExtensionContext,
  repeat: boolean = true
) {
  await prosLogger.log("OneClick", "Getting paths for integrated terminal");
  let [cliExecPath, toolchainPath, vexcomPath] =
    getIntegratedTerminalPaths(context);

  // return if the path is already configured
  const addQuotes =
    getOperatingSystem() === "macos" && !os.cpus()[0].model.includes("Apple M");

99 lines remaining in ancestor node. Read the file to see all.

async function configurePaths( ) › L745-747

  if (repeat) {
    configurePaths(context, false); // recursive call to ensure that the path is configured. This is necessary because Macs are stupid and need the PATH updated twice for some reason.
  }

Matches in pros-vsc/src/workspace_utils.ts

L1-11

import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";
import { promisify } from "util";
import { getOperatingSystem } from "./one-click/install";
import { getChildProcessProsToolchainPath } from "./one-click/path";
import { configurePaths } from "./one-click/install";

/**
 * This function searches a directory of the workspace for a file with the given name
 *

420 lines remaining in ancestor node. Read the file to see all.

const getProsTerminal › L208-212


  // If there is not already a terminal named "PROS Terminal" or it does not have the correct path, create a new one.
  await configurePaths(context); // Configure the paths (see install.ts) so that everything runs properly when you click a button

  // Create a new terminal with the correct path, return it.

Agent

Use Tool: read_file (call_fE1P1F6vMdLOjmeejUlBA6UG)

{
  "path": "pros-vsc/src/one-click/install.ts",
  "start_line": 600,
  "end_line": 800
}

Tool Results: call_fE1P1F6vMdLOjmeejUlBA6UG

    }

    await prosLogger.log(
      "OneClick",
      `Verifying that CLI and Toolchain are working`
    );
    await chmod(globalPath.fsPath, system);
    await prosLogger.log("OneClick", `Configuring environment variables`);
    await configurePaths(context).catch((e) => {
      prosLogger.log("OneClick", e, "ERROR");
    });

    // Ensure that toolchain and cli are working
    let cliSuccess = await verifyCli();
    let toolchainSuccess = await verifyToolchain();
    let vexcomSuccess = await verifyVexcom();
    if (cliSuccess && toolchainSuccess && vexcomSuccess) {
      vscode.window.showInformationMessage(
        "CLI and Toolchain are working!"
      );
    } else {
      vscode.window.showErrorMessage(
        `${cliSuccess && vexcomSuccess ? "" : "CLI"}
        ${!cliSuccess && !toolchainSuccess && !vexcomSuccess ? " and " : ""}
        ${toolchainSuccess ? "" : "Toolchain"}
        Installation Failed!`
      );
      vscode.window.showInformationMessage(
        `Please try installing again! If this problem persists, consider trying an alternative install method: https://pros.cs.purdue.edu/v5/getting-started/${system}.html`
      );
    }
  } catch (err: any) {
    vscode.window.showInformationMessage("FATAL ERROR DURING VERIFICATION");
    prosLogger.log("OneClick", err, "ERROR");
  }
}

); }

export async function configurePaths( context: vscode.ExtensionContext, repeat: boolean = true ) { await prosLogger.log("OneClick", "Getting paths for integrated terminal"); let [cliExecPath, toolchainPath, vexcomPath] = getIntegratedTerminalPaths(context);

// return if the path is already configured const addQuotes = getOperatingSystem() === "macos" && !os.cpus()[0].model.includes("Apple M"); // Check if user has CLI installed through one-click or other means. await prosLogger.log("OneClick", "Checking How CLI is installed"); let [version, isOneClickInstall] = await getCurrentVersion( path.join( ${addQuotes ? ": ""}${cliExecPath}${addQuotes ?" : ""}, "pros" ) ); let [currentToolchainVersion, isToolchainOneClickInstall] = await getToolchainVersion( path.join( ${addQuotes ? ": ""}${toolchainPath}${addQuotes ?" : ""}, "bin", "arm-none-eabi-g++" ) ); process.env["PROS_VSCODE_FLAGS"] = semver.gte( semver.coerce(version) ?? "0.0.0", "3.2.4" ) ? "--no-sentry --no-analytics" : ""; await prosLogger.log( "OneClick", CLI is installed through ${ isOneClickInstall ? "one-click" : "other means" } with version ${version} ); await prosLogger.log( "OneClick", Toolchain is installed through ${ isToolchainOneClickInstall ? "one-click" : "other means" } with version ${currentToolchainVersion} ); console.log(${isOneClickInstall} | ${version});

PATH_SEP = getOperatingSystem() === "windows" ? ";" : ":";

if (PATH_SEP === ":") { cliExecPath = cliExecPath.replace(/\/g, ""); toolchainPath = toolchainPath.replace(/\/g, ""); vexcomPath = vexcomPath.replace(/\/g, ""); } TOOLCHAIN = process.env["PROS_TOOLCHAIN"] ?? toolchainPath; // Set CLI environmental variable file location CLI_EXEC_PATH = cliExecPath;

let pathCliCount: number = process.env["PATH"]?.split(PATH_SEP).filter((x) => x.includes(cliExecPath)) .length ?? 0; let pathToolchainCount: number = process.env["PATH"] ?.split(PATH_SEP) .filter((x) => x.includes(toolchainPath)).length ?? 0; let pathVexcomCount: number = process.env["PATH"]?.split(PATH_SEP).filter((x) => x.includes(vexcomPath)) .length ?? 0;

prosLogger.log("OneClick", CLI path count: ${pathCliCount}); prosLogger.log("OneClick", Toolchain path count: ${pathToolchainCount}); prosLogger.log("OneClick", Vexcom path count: ${pathVexcomCount}); console.log(CLI path count: ${pathCliCount}); console.log(Toolchain path count: ${pathToolchainCount}); console.log(Vexcom path count: ${pathVexcomCount}); if ( pathCliCount > 2 && pathToolchainCount > 2 && pathVexcomCount > 2 && process.env["PROS_TOOLCHAIN"]?.includes(TOOLCHAIN) ) { console.log("path already configured"); await prosLogger.log("OneClick", "PATH is already configured"); return; } // Prepend CLI and TOOLCHAIN to path await prosLogger.log("OneClick", "Appending CLI and TOOLCHAIN to PATH"); await prosLogger.log("OneClick", CLI Executable Path: ${cliExecPath}); process.env.PATH = ${process.env.PATH}; // bypass compile errors await prosLogger.log("OneClick", process.env.PATH ?? "no PATH", "INFO"); process.env.PATH = ${cliExecPath}${PATH_SEP} + ${path.join(toolchainPath, "bin")}${PATH_SEP} + ${vexcomPath}${PATH_SEP} + ${process.env.PATH.replace(/\"/g, "")}; await prosLogger.log("OneClick", process.env.PATH ?? "no PATH", "INFO"); // Make PROS_TOOLCHAIN variable await prosLogger.log("OneClick", "Setting PROS_TOOLCHAIN"); process.env.PROS_TOOLCHAIN = TOOLCHAIN; await prosLogger.log( "OneClick", "PROS_TOOLCHAIN: " + process.env.PROS_TOOLCHAIN, "INFO" );

process.env.LC_ALL = "en_US.utf-8"; if (repeat) { configurePaths(context, false); // recursive call to ensure that the path is configured. This is necessary because Macs are stupid and need the PATH updated twice for some reason. } }

async function verifyCli() { var command = pros --version ${process.env["PROS_VSCODE_FLAGS"]}; await prosLogger.log("OneClick", Verifying CLI with command ${command}); try { const { stdout, stderr } = await promisify(child_process.exec)(command, { timeout: 30000, env: { ...process.env, // eslint-disable-next-line @typescript-eslint/naming-convention PATH: getChildProcessPath(), }, }); if (stderr) { await prosLogger.log( "OneClick", CLI verification failed with error ${stderr}, "ERROR" ); console.error(stderr); } return stdout.startsWith("pros, version"); } catch (err) { prosLogger.log( "OneClick", CLI verification failed with error ${err}, "ERROR" ); console.error(err); return false; } }

async function verifyToolchain() { await prosLogger.log("OneClick", "Verifying TOOLCHAIN");

let toolchainPath = getChildProcessProsToolchainPath() ?? ""; if (!toolchainPath) { await prosLogger.log("OneClick", "No valid toolchain path found", "error"); return false; }

await prosLogger.log("OneClick", Using toolchain path ${toolchainPath});

let command = "${path.join( toolchainPath, "bin", "arm-none-eabi-g++" )}" --version; console.log(command); await prosLogger.log( "OneClick",

Agent

The magic really boils down to how we cheat the Windows shell into “seeing” a whole folder‐full of Linux-flavored executables, by prepending our PROS toolchain and CLI directories onto the user’s PATH and then spinning up the integrated terminal with that augmented environment.

  1. We calculate three install paths (CLI, toolchain, vexcom) in

    export const getIntegratedTerminalPaths = (
      context: vscode.ExtensionContext
    ): [string, string, string] => {
      const globalPath = context.globalStorageUri.fsPath;
      const system = getOperatingSystem();
    
      // On Windows this ends up pointing at:
      //    <storage>/install/pros-cli-windows
      let cliExecPath = path.join(globalPath, "install", `pros-cli-${system}`);
    
      // and
      //    <storage>/install/pros-toolchain-windows-formatted/usr
      let toolchainPath = path.join(
        globalPath,
        "install",
        `pros-toolchain-windows-formatted`,
        "usr"
      );
    
      // …
      return [cliExecPath, toolchainPath, vexcomPath];
    };
    
  2. During activation (and again every time you open the “PROS Terminal”), we call

    // Prepend our CLI & toolchain into the PATH so that all their GNU‐style
    // binaries (sh, ls, grep, make, arm-none-eabi-g++, pros, …) are first in line.
    process.env.PATH =
      `${cliExecPath}${PATH_SEP}` +
      `${path.join(toolchainPath, "bin")}${PATH_SEP}` +
      `${vexcomPath}${PATH_SEP}` +
      `${process.env.PATH.replace(/\"/g, "")}`;
    
    // Export PROS_TOOLCHAIN for child processes
    process.env.PROS_TOOLCHAIN = TOOLCHAIN;
    
  3. Finally we hand that patched process.env off to VS Code when creating the terminal:

      // Ensure our PROS CLI + GNU toolchain are on the PATH
      await configurePaths(context);
    
      // Launch the terminal with our modified env
      return vscode.window.createTerminal({
        name: "PROS Terminal",
        env: process.env,
      });
    });
    

Because the “windows-formatted” toolchain bundle actually contains Windows binaries of the familiar GNU/UNIX tools (e.g. sh.exe, ls.exe, grep.exe, make.exe, arm-none-eabi-g++.exe, etc.) and we stick its bin folder at the front of the PATH, you can open “PROS Terminal” on Windows and use essentially the same Linux/UNIX commands you’d have on macOS or Linux.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment