Blog

  • Checklist: Real-Time Code Context Capture & DB Integration, A VS Code Extension(Phase 1)

    Build a VS Code Extension for Real-Time Code Context Capture & DB Integration (Phase 1)


    Introduction

    In today’s development landscape, providing real-time, context-aware code suggestions is crucial for productivity. This guide details Phase 1 of our project: building a VS Code extension that uses VS Code’s built-in language server to capture definitions and references from your codebase and store this context in a local SQLite database. The enriched context can help tools like GitHub Copilot debug and provide smarter suggestions.

    Follow this step-by-step checklist to set up your environment, implement the extension, and verify that everything is working as expected.


    Phase 1: Initial Extension Development & Database Integration

    Goal:
    Leverage VS Code’s language server to capture real-time code context and store the information in a local SQLite database.


    1. Set Up Your Development Environment

    • Install Node.js:
      Download and install Node.js from nodejs.org.
    • Install VS Code:
      Download and install Visual Studio Code from code.visualstudio.com.
    • Install TypeScript:
      Open your terminal and run: npm install -g typescript
    • Install Yeoman & VS Code Extension Generator:
      Run the following command: npm install -g yo generator-code
    • Create a New VS Code Extension Project:
      In your terminal, run: yo code Choose TypeScript as the language when prompted. This sets up the basic structure for your extension.

    2. Project Structure & Dependencies

    • Organize Your Project Folders:
      Ensure your project contains directories such as src/ for your TypeScript source files and out/ for the compiled JavaScript.
    • Configure package.json:
      Add the required dependencies. Below is an example of a complete package.json: { "name": "copilot-context-extension", "displayName": "Copilot Context Extension", "description": "Capture code context using VS Code’s language server and store it in a local SQLite database.", "version": "0.0.1", "engines": { "vscode": "^1.50.0" }, "activationEvents": [ "onCommand:extension.storeFunctionContext" ], "main": "./out/extension.js", "contributes": { "commands": [ { "command": "extension.storeFunctionContext", "title": "Store Function Context" } ] }, "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -p ./" }, "dependencies": { "sqlite3": "^5.1.2" }, "devDependencies": { "typescript": "^4.0.3", "@types/node": "^12.11.7", "@types/vscode": "^1.50.0" } }

    3. Implement Core Functionality

    • Create the Command in extension.ts:
      In your src/extension.ts file, implement the command that captures the symbol under the cursor and collects its definitions and references. Paste the following code into extension.ts: import * as vscode from 'vscode'; import * as sqlite3 from 'sqlite3'; let db: sqlite3.Database; // Initialize the SQLite database function initDatabase() { db = new sqlite3.Database('copilot_context.db', (err) => { if (err) { console.error("Failed to open database:", err.message); } else { db.run(`CREATE TABLE IF NOT EXISTS function_context ( id INTEGER PRIMARY KEY AUTOINCREMENT, function_name TEXT, file_path TEXT, line INTEGER, character INTEGER, context_type TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP )`, (err) => { if (err) { console.error("Failed to create table:", err.message); } }); } }); } // Store context data into the database function storeContext(functionName: string, filePath: string, line: number, character: number, contextType: string) { const stmt = db.prepare( `INSERT INTO function_context (function_name, file_path, line, character, context_type) VALUES (?, ?, ?, ?, ?)` ); stmt.run(functionName, filePath, line, character, contextType, (err) => { if (err) { console.error("Error storing context:", err.message); } }); stmt.finalize(); } export function activate(context: vscode.ExtensionContext) { // Initialize database upon activation initDatabase(); let disposable = vscode.commands.registerCommand('extension.storeFunctionContext', async () => { const editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showErrorMessage("No active editor found."); return; } const document = editor.document; const position = editor.selection.active; const wordRange = document.getWordRangeAtPosition(position); if (!wordRange) { vscode.window.showErrorMessage("No symbol selected."); return; } const selectedWord = document.getText(wordRange); // Retrieve definitions using VS Code's built-in command. const definitions = await vscode.commands.executeCommand<vscode.Location[]>( 'vscode.executeDefinitionProvider', document.uri, position ); // Retrieve references using VS Code's built-in command. const references = await vscode.commands.executeCommand<vscode.Location[]>( 'vscode.executeReferenceProvider', document.uri, position ); // Store definitions in the database. if (definitions && definitions.length > 0) { definitions.forEach(def => { storeContext( selectedWord, def.uri.fsPath, def.range.start.line + 1, def.range.start.character + 1, "definition" ); }); } else { vscode.window.showInformationMessage("No definitions found for " + selectedWord); } // Store references in the database. if (references && references.length > 0) { references.forEach(ref => { storeContext( selectedWord, ref.uri.fsPath, ref.range.start.line + 1, ref.range.start.character + 1, "reference" ); }); } else { vscode.window.showInformationMessage("No references found for " + selectedWord); } vscode.window.showInformationMessage(`Stored context for "${selectedWord}" in the database.`); }); context.subscriptions.push(disposable); } export function deactivate() { if (db) { db.close(); } }
    • Configure the Command Trigger:
      Ensure your command appears in the Command Palette or is accessible via a right-click/context menu as configured in your package.json.

    4. Database Integration

    • Database Initialization:
      The above code creates (or opens) a SQLite database file named copilot_context.db in the project’s root directory.
    • Create the Database Table:
      A table called function_context is created with columns for:
      • Function name
      • File path
      • Line number
      • Character position
      • Context type (definition or reference)
      • Timestamp
    • Insert Captured Context:
      The storeContext function inserts each piece of captured data into the table.

    5. Testing & Debugging

    • Compile Your Extension:
      Run the following command in your terminal: npm run compile
    • Launch in Debug Mode:
      Open VS Code, press F5 to launch a new Extension Development Host.
    • Test the Functionality:
      • Open a sample code file in the new window.
      • Right-click on a function (or trigger via the keyboard shortcut) and select the “Store Function Context” command.
      • Verify that the extension captures the symbol’s definitions and references, storing them in the database.
    • Use VS Code’s Debugging Tools:
      Check the debug console for errors or messages and set breakpoints in extension.ts if needed.

    6. Documentation & Final Checks

    • Create a README File:
      Include detailed instructions on:
      • Installing dependencies (npm install)
      • Compiling the project
      • Launching the extension in debug mode
      • How to trigger the command and check the database (copilot_context.db)
    • Address Common Questions:
      • Q: What if I don’t see any output?
        A: Ensure the command is bound correctly and that you’re running the extension in the Extension Development Host.
      • Q: How do I view the database entries?
        A: Use an SQLite viewer to open the copilot_context.db file located in the project folder.
      • Q: What if the database isn’t created?
        A: Check the debug console for errors related to SQLite initialization or file permissions.
    • Final Testing:
      Confirm that the extension passes the Testing & Debugging step and that GitHub Copilot can leverage the enriched context for better debugging.

    Conclusion

    By following this checklist, your team will have a fully functioning Phase 1 VS Code extension that captures real-time code context and stores it in a local database. This robust foundation not only enhances Copilot’s debugging capabilities but also sets the stage for future integration of historical change tracking and more advanced features.