[ide-mode] Send the cursor and selected text from the IDE server (#4621)

This commit is contained in:
christine betts 2025-07-24 19:54:41 +00:00 committed by GitHub
parent f9930c2d36
commit 4e376c0447
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 27 additions and 3 deletions

View File

@ -15,7 +15,6 @@ let log: (message: string) => void = () => {};
export async function activate(context: vscode.ExtensionContext) {
logger = vscode.window.createOutputChannel('Gemini CLI IDE Companion');
log = createLogger(context, logger);
log('Extension activated');
ideServer = new IDEServer(log);
try {

View File

@ -18,6 +18,7 @@ import { RecentFilesManager } from './recent-files-manager.js';
const MCP_SESSION_ID_HEADER = 'mcp-session-id';
const IDE_SERVER_PORT_ENV_VAR = 'GEMINI_CLI_IDE_SERVER_PORT';
const MAX_SELECTED_TEXT_LENGTH = 16384; // 16 KiB limit
function sendOpenFilesChangedNotification(
transport: StreamableHTTPServerTransport,
@ -29,6 +30,19 @@ function sendOpenFilesChangedNotification(
editor && editor.document.uri.scheme === 'file'
? editor.document.uri.fsPath
: '';
const selection = editor?.selection;
const cursor = selection
? {
// This value is a zero-based index, but the vscode IDE is one-based.
line: selection.active.line + 1,
character: selection.active.character,
}
: undefined;
let selectedText = editor?.document.getText(selection) ?? undefined;
if (selectedText && selectedText.length > MAX_SELECTED_TEXT_LENGTH) {
selectedText =
selectedText.substring(0, MAX_SELECTED_TEXT_LENGTH) + '... [TRUNCATED]';
}
const notification: JSONRPCNotification = {
jsonrpc: '2.0',
method: 'ide/openFilesChanged',
@ -37,6 +51,8 @@ function sendOpenFilesChangedNotification(
recentOpenFiles: recentFilesManager.recentFiles.filter(
(file) => file.filePath !== filePath,
),
cursor,
selectedText,
},
};
log(
@ -69,7 +85,7 @@ export class IDEServer {
const mcpServer = createMcpServer();
const recentFilesManager = new RecentFilesManager(context);
const disposable = recentFilesManager.onDidChange(() => {
const onDidChangeSubscription = recentFilesManager.onDidChange(() => {
for (const transport of Object.values(transports)) {
sendOpenFilesChangedNotification(
transport,
@ -78,7 +94,7 @@ export class IDEServer {
);
}
});
context.subscriptions.push(disposable);
context.subscriptions.push(onDidChangeSubscription);
app.post('/mcp', async (req: Request, res: Response) => {
const sessionId = req.headers[MCP_SESSION_ID_HEADER] as

View File

@ -28,6 +28,7 @@ vi.mock('vscode', () => ({
}),
window: {
onDidChangeActiveTextEditor: vi.fn(),
onDidChangeTextEditorSelection: vi.fn(),
},
workspace: {
onDidDeleteFiles: vi.fn(),

View File

@ -47,11 +47,19 @@ export class RecentFilesManager {
this.add(newUri);
}
});
const selectionWatcher = vscode.window.onDidChangeTextEditorSelection(
() => {
this.fireWithDebounce();
},
);
context.subscriptions.push(
editorWatcher,
deleteWatcher,
closeWatcher,
renameWatcher,
selectionWatcher,
);
}