Skip to content

Conversation

@waruqi
Copy link
Member

@waruqi waruqi commented Jan 3, 2026

image image

@gemini-code-assist
Copy link

Summary of Changes

Hello @waruqi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly expands the debugging capabilities of the XMake VSCode extension by integrating support for LLDB Debug Adapter Protocol and GDB Debug Adapter Protocol. It also includes a substantial refactoring of internal path resolution mechanisms, moving asset and resource path handling into a dedicated utility module to streamline development and ensure robust operation across different environments.

Highlights

  • Debugger Protocol Support: Added support for LLDB Debug Adapter Protocol (DAP) and GDB Debug Adapter Protocol (DAP), allowing users to select these new debugger types in the extension's configuration.
  • Path Resolution Refactoring: Introduced a new utils.ts module to centralize and standardize the resolution of paths for assets, resources, and templates, improving maintainability and ensuring correct paths in both development and compiled environments.
  • Improved Debugger Configuration: Enhanced the debugger configuration logic to dynamically set up launch configurations for LLDB DAP and GDB DAP, including environment variable handling and checks for installed extensions.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@waruqi waruqi merged commit 00f3857 into dev Jan 3, 2026
6 checks passed
@waruqi waruqi deleted the debug branch January 3, 2026 10:02
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for LLDB DAP and GDB DAP debuggers, expanding the available debugging options. The package.json was updated to include these new debugger types, and src/debugger.ts and src/launchDebugger.ts were modified to handle their specific configurations, including environment variable parsing. A new src/utils.ts file was added to centralize path resolution for assets, resources, and templates, and existing code across src/completion.ts, src/explorer.ts, src/launchDebugger.ts, and src/xmake.ts was refactored to utilize these new utility functions. Review comments identified a critical bug in src/xmake.ts where target_informations.lua was incorrectly used to list all targets, which needs to be reverted to a script that returns an array of target names. Additionally, the reviewer noted redundant assignments and hardcoded .exe extensions in the lldb-dap and gdb-dap debug configurations within src/debugger.ts, recommending the use of path.basename(targetInformations.path) for cross-platform compatibility. Refactoring of duplicated environment variable processing logic and more accurate type assertions were also suggested for src/debugger.ts. Finally, the src/utils.ts file was advised to refactor its path resolution logic into a single helper function to improve maintainability.

Comment on lines +1514 to 1517
let getTargetInformationsScript = utils.getAssetsScriptPath("target_informations.lua");
if (fs.existsSync(getTargetInformationsScript)) {
targets = (await process.iorunv(config.executable, ["l", getTargetInformationsScript], { "COLORTERM": "nocolor" }, config.workingDirectory)).stdout.trim();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The script target_informations.lua is being used here to get a list of all targets. However, when called without arguments, this script returns information for only the default target as a JSON object, not an array of all target names. This will cause a runtime error when targetlist.forEach is called on the resulting object.

You should use a script that returns a list of all target names. The previous implementation used assets/targets.lua, which seems correct. Please revert this to use a script that lists all targets.

Suggested change
let getTargetInformationsScript = utils.getAssetsScriptPath("target_informations.lua");
if (fs.existsSync(getTargetInformationsScript)) {
targets = (await process.iorunv(config.executable, ["l", getTargetInformationsScript], { "COLORTERM": "nocolor" }, config.workingDirectory)).stdout.trim();
}
let getTargetsScript = utils.getAssetsScriptPath("targets.lua"); // Or another script that lists all target names
if (fs.existsSync(getTargetsScript)) {
targets = (await process.iorunv(config.executable, ["l", getTargetsScript], { "COLORTERM": "nocolor" }, config.workingDirectory)).stdout.trim();
}

Comment on lines +272 to +286
// Switch to LLDB DAP if needed
if (config.debugConfigType == "lldb-dap") {
config.type = 'lldb-dap';
config.stopOnEntry = config.stopOnEntry;
// LLDB DAP doesn't support newExternal
if (config.terminal == 'newExternal') {
config.terminal = 'external';
}

// LLDB DAP use program key for search a running process
if (config.request == 'attach') {
config.stopOnEntry = false;
config.program = `${targetInformations.name}.exe`;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This block has a couple of issues:

  1. The assignment config.stopOnEntry = config.stopOnEntry; is redundant and can be removed for clarity.
  2. Hardcoding the .exe extension for the program name in attach mode will fail on non-Windows platforms. You should use path.basename(targetInformations.path) to get the platform-correct executable name.

I've suggested the changes for the lldb-dap block; please apply similar changes for the gdb-dap block.

        // Switch to LLDB DAP if needed
        if (config.debugConfigType == "lldb-dap") {
            config.type = 'lldb-dap';
            // LLDB DAP doesn't support newExternal
            if (config.terminal == 'newExternal') {
                config.terminal = 'external';
            }

            // LLDB DAP use program key for search a running process
            if (config.request == 'attach') {
                config.stopOnEntry = false;
                config.program = path.basename(targetInformations.path);
            }
        }

Comment on lines +288 to +302
// Switch to GDB DAP if needed
if (config.debugConfigType == "gdb-dap") {
config.type = 'gdb';
config.stopOnEntry = config.stopOnEntry;
// GDB DAP doesn't support newExternal
if (config.terminal == 'newExternal') {
config.terminal = 'external';
}

// GDB DAP use program key for search a running process
if (config.request == 'attach') {
config.stopOnEntry = false;
config.program = `${targetInformations.name}.exe`;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the lldb-dap block, this block has a redundant assignment and hardcodes the .exe extension.

  1. The assignment config.stopOnEntry = config.stopOnEntry; is redundant.
  2. Hardcoding .exe for attach mode will fail on non-Windows platforms. Please use path.basename(targetInformations.path) instead.
        // Switch to GDB DAP if needed
        if (config.debugConfigType == "gdb-dap") {
            config.type = 'gdb';
            // GDB DAP doesn't support newExternal
            if (config.terminal == 'newExternal') {
                config.terminal = 'external';
            }

            // GDB DAP use program key for search a running process
            if (config.request == 'attach') {
                config.stopOnEntry = false;
                config.program = path.basename(targetInformations.path);
            }
        }

Comment on lines +122 to +158
} else if (lldbdap) {
// LLDB DAP configuration
var envs = {};
for (let item of (targetRunEnvs as Array<Object>)) {
let map = item as Map<String, String>;
if (map) {
let name = map["name"];
let value = map["value"];
if (name && value) {
envs[name] = value;
}
}
}
debugConfig = {
name: `launch: ${targetName}`,
type: 'lldb-dap',
request: 'launch',
program: targetProgram,
args: args,
stopAtEntry: true,
cwd: targetRunDir,
env: envs,
externalConsole: false,
};
} else if (gdbdap) {
// GDB DAP configuration
var gdbEnvs = [];
for (let item of (targetRunEnvs as Array<Object>)) {
let map = item as Map<String, String>;
if (map) {
let name = map["name"];
let value = map["value"];
if (name && value) {
gdbEnvs.push({name: name, value: value});
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's significant code duplication in how environment variables are processed for codelldb, lldbdap, and gdbdap. The loops are very similar and can be refactored into a helper function to improve maintainability and reduce redundancy.

Additionally, the type assertion item as Map<String, String> is not accurate. The targetRunEnvs is an array of objects like { name: string, value: string }. Using item as { name: string, value: string } would be more precise. The use of String (capital S) is also unconventional for type annotations in TypeScript; string is preferred.

Consider creating a utility function to handle environment variable processing for different debugger formats.

Comment on lines +20 to +60
// get assets script path
export function getAssetsScriptPath(scriptName: string): string {
// In development mode (running from source), __dirname points to src/
// In compiled extension (running from out), __dirname points to out/
// So we need to handle both cases
if (__dirname.endsWith('src')) {
// Development mode: go up two levels from src/
return path.resolve(__dirname, "..", "..", "assets", scriptName);
} else {
// Compiled mode: go up one level from out/
return path.resolve(__dirname, "..", "assets", scriptName);
}
}

// get res directory path
export function getResourcePath(resourceName: string = ""): string {
// In development mode (running from source), __dirname points to src/
// In compiled extension (running from out), __dirname points to out/
// So we need to handle both cases
if (__dirname.endsWith('src')) {
// Development mode: go up two levels from src/
return path.resolve(__dirname, "..", "..", "res", resourceName);
} else {
// Compiled mode: go up one level from out/
return path.resolve(__dirname, "..", "res", resourceName);
}
}

// get template directory path
export function getTemplatePath(templateName: string = ""): string {
// In development mode (running from source), __dirname points to src/
// In compiled extension (running from out), __dirname points to out/
// So we need to handle both cases
if (__dirname.endsWith('src')) {
// Development mode: go up two levels from src/
return path.resolve(__dirname, "..", "..", "assets", "newfiles", templateName);
} else {
// Compiled mode: go up one level from out/
return path.resolve(__dirname, "..", "assets", "newfiles", templateName);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The functions getAssetsScriptPath, getResourcePath, and getTemplatePath contain duplicated logic for determining the base path based on whether the extension is running in development or compiled mode. This can be refactored into a single private helper function to improve maintainability. For example:

function getBasePath(): string {
    if (__dirname.endsWith('src')) {
        return path.resolve(__dirname, "..", "..");
    } else {
        return path.resolve(__dirname, "..");
    }
}

export function getAssetsScriptPath(scriptName: string): string {
    return path.join(getBasePath(), "assets", scriptName);
}
// ... and so on for other functions

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants