diff options
| author | christine betts <[email protected]> | 2025-07-21 20:52:02 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-21 20:52:02 +0000 |
| commit | 1969d805f2fd559e2227a8822de5be66d3d8a184 (patch) | |
| tree | e9a84b780a87a67778730b806fad0df770aebec6 /packages/core/src/services | |
| parent | d7a57d85a39535e84bba7e65eb02dcb627b9cb81 (diff) | |
[ide-mode] Use active files and selected text in user prompt (#4614)
Diffstat (limited to 'packages/core/src/services')
| -rw-r--r-- | packages/core/src/services/ideContext.test.ts | 78 | ||||
| -rw-r--r-- | packages/core/src/services/ideContext.ts | 50 |
2 files changed, 64 insertions, 64 deletions
diff --git a/packages/core/src/services/ideContext.test.ts b/packages/core/src/services/ideContext.test.ts index 9aa4c013..1cb09c53 100644 --- a/packages/core/src/services/ideContext.test.ts +++ b/packages/core/src/services/ideContext.test.ts @@ -16,59 +16,59 @@ describe('ideContext - Active File', () => { }); it('should return undefined initially for active file context', () => { - expect(ideContext.getActiveFileContext()).toBeUndefined(); + expect(ideContext.getOpenFilesContext()).toBeUndefined(); }); it('should set and retrieve the active file context', () => { const testFile = { - filePath: '/path/to/test/file.ts', - cursor: { line: 5, character: 10 }, + activeFile: '/path/to/test/file.ts', + selectedText: '1234', }; - ideContext.setActiveFileContext(testFile); + ideContext.setOpenFilesContext(testFile); - const activeFile = ideContext.getActiveFileContext(); + const activeFile = ideContext.getOpenFilesContext(); expect(activeFile).toEqual(testFile); }); it('should update the active file context when called multiple times', () => { const firstFile = { - filePath: '/path/to/first.js', - cursor: { line: 1, character: 1 }, + activeFile: '/path/to/first.js', + selectedText: '1234', }; - ideContext.setActiveFileContext(firstFile); + ideContext.setOpenFilesContext(firstFile); const secondFile = { - filePath: '/path/to/second.py', + activeFile: '/path/to/second.py', cursor: { line: 20, character: 30 }, }; - ideContext.setActiveFileContext(secondFile); + ideContext.setOpenFilesContext(secondFile); - const activeFile = ideContext.getActiveFileContext(); + const activeFile = ideContext.getOpenFilesContext(); expect(activeFile).toEqual(secondFile); }); it('should handle empty string for file path', () => { const testFile = { - filePath: '', - cursor: { line: 0, character: 0 }, + activeFile: '', + selectedText: '1234', }; - ideContext.setActiveFileContext(testFile); - expect(ideContext.getActiveFileContext()).toEqual(testFile); + ideContext.setOpenFilesContext(testFile); + expect(ideContext.getOpenFilesContext()).toEqual(testFile); }); it('should notify subscribers when active file context changes', () => { const subscriber1 = vi.fn(); const subscriber2 = vi.fn(); - ideContext.subscribeToActiveFile(subscriber1); - ideContext.subscribeToActiveFile(subscriber2); + ideContext.subscribeToOpenFiles(subscriber1); + ideContext.subscribeToOpenFiles(subscriber2); const testFile = { - filePath: '/path/to/subscribed.ts', + activeFile: '/path/to/subscribed.ts', cursor: { line: 15, character: 25 }, }; - ideContext.setActiveFileContext(testFile); + ideContext.setOpenFilesContext(testFile); expect(subscriber1).toHaveBeenCalledTimes(1); expect(subscriber1).toHaveBeenCalledWith(testFile); @@ -77,10 +77,10 @@ describe('ideContext - Active File', () => { // Test with another update const newFile = { - filePath: '/path/to/new.js', - cursor: { line: 1, character: 1 }, + activeFile: '/path/to/new.js', + selectedText: '1234', }; - ideContext.setActiveFileContext(newFile); + ideContext.setOpenFilesContext(newFile); expect(subscriber1).toHaveBeenCalledTimes(2); expect(subscriber1).toHaveBeenCalledWith(newFile); @@ -92,21 +92,21 @@ describe('ideContext - Active File', () => { const subscriber1 = vi.fn(); const subscriber2 = vi.fn(); - const unsubscribe1 = ideContext.subscribeToActiveFile(subscriber1); - ideContext.subscribeToActiveFile(subscriber2); + const unsubscribe1 = ideContext.subscribeToOpenFiles(subscriber1); + ideContext.subscribeToOpenFiles(subscriber2); - ideContext.setActiveFileContext({ - filePath: '/path/to/file1.txt', - cursor: { line: 1, character: 1 }, + ideContext.setOpenFilesContext({ + activeFile: '/path/to/file1.txt', + selectedText: '1234', }); expect(subscriber1).toHaveBeenCalledTimes(1); expect(subscriber2).toHaveBeenCalledTimes(1); unsubscribe1(); - ideContext.setActiveFileContext({ - filePath: '/path/to/file2.txt', - cursor: { line: 2, character: 2 }, + ideContext.setOpenFilesContext({ + activeFile: '/path/to/file2.txt', + selectedText: '1234', }); expect(subscriber1).toHaveBeenCalledTimes(1); // Should not be called again expect(subscriber2).toHaveBeenCalledTimes(2); @@ -114,27 +114,27 @@ describe('ideContext - Active File', () => { it('should allow the cursor to be optional', () => { const testFile = { - filePath: '/path/to/test/file.ts', + activeFile: '/path/to/test/file.ts', }; - ideContext.setActiveFileContext(testFile); + ideContext.setOpenFilesContext(testFile); - const activeFile = ideContext.getActiveFileContext(); + const activeFile = ideContext.getOpenFilesContext(); expect(activeFile).toEqual(testFile); }); it('should clear the active file context', () => { const testFile = { - filePath: '/path/to/test/file.ts', - cursor: { line: 5, character: 10 }, + activeFile: '/path/to/test/file.ts', + selectedText: '1234', }; - ideContext.setActiveFileContext(testFile); + ideContext.setOpenFilesContext(testFile); - expect(ideContext.getActiveFileContext()).toEqual(testFile); + expect(ideContext.getOpenFilesContext()).toEqual(testFile); - ideContext.clearActiveFileContext(); + ideContext.clearOpenFilesContext(); - expect(ideContext.getActiveFileContext()).toBeUndefined(); + expect(ideContext.getOpenFilesContext()).toBeUndefined(); }); }); diff --git a/packages/core/src/services/ideContext.ts b/packages/core/src/services/ideContext.ts index 0aab1e8d..349bff59 100644 --- a/packages/core/src/services/ideContext.ts +++ b/packages/core/src/services/ideContext.ts @@ -10,7 +10,6 @@ import { z } from 'zod'; * The reserved server name for the IDE's MCP server. */ export const IDE_SERVER_NAME = '_ide_server'; - /** * Zod schema for validating a cursor position. */ @@ -23,8 +22,9 @@ export type Cursor = z.infer<typeof CursorSchema>; /** * Zod schema for validating an active file context from the IDE. */ -export const ActiveFileSchema = z.object({ - filePath: z.string(), +export const OpenFilesSchema = z.object({ + activeFile: z.string(), + selectedText: z.string().optional(), cursor: CursorSchema.optional(), recentOpenFiles: z .array( @@ -35,17 +35,17 @@ export const ActiveFileSchema = z.object({ ) .optional(), }); -export type ActiveFile = z.infer<typeof ActiveFileSchema>; +export type OpenFiles = z.infer<typeof OpenFilesSchema>; /** - * Zod schema for validating the 'ide/activeFileChanged' notification from the IDE. + * Zod schema for validating the 'ide/openFilesChanged' notification from the IDE. */ -export const ActiveFileNotificationSchema = z.object({ - method: z.literal('ide/activeFileChanged'), - params: ActiveFileSchema, +export const OpenFilesNotificationSchema = z.object({ + method: z.literal('ide/openFilesChanged'), + params: OpenFilesSchema, }); -type ActiveFileSubscriber = (activeFile: ActiveFile | undefined) => void; +type OpenFilesSubscriber = (openFiles: OpenFiles | undefined) => void; /** * Creates a new store for managing the IDE's active file context. @@ -55,41 +55,41 @@ type ActiveFileSubscriber = (activeFile: ActiveFile | undefined) => void; * @returns An object with methods to interact with the active file context. */ export function createIdeContextStore() { - let activeFileContext: ActiveFile | undefined = undefined; - const subscribers = new Set<ActiveFileSubscriber>(); + let openFilesContext: OpenFiles | undefined = undefined; + const subscribers = new Set<OpenFilesSubscriber>(); /** * Notifies all registered subscribers about the current active file context. */ function notifySubscribers(): void { for (const subscriber of subscribers) { - subscriber(activeFileContext); + subscriber(openFilesContext); } } /** * Sets the active file context and notifies all registered subscribers of the change. - * @param newActiveFile The new active file context from the IDE. + * @param newOpenFiles The new active file context from the IDE. */ - function setActiveFileContext(newActiveFile: ActiveFile): void { - activeFileContext = newActiveFile; + function setOpenFilesContext(newOpenFiles: OpenFiles): void { + openFilesContext = newOpenFiles; notifySubscribers(); } /** * Clears the active file context and notifies all registered subscribers of the change. */ - function clearActiveFileContext(): void { - activeFileContext = undefined; + function clearOpenFilesContext(): void { + openFilesContext = undefined; notifySubscribers(); } /** * Retrieves the current active file context. - * @returns The `ActiveFile` object if a file is active, otherwise `undefined`. + * @returns The `OpenFiles` object if a file is active, otherwise `undefined`. */ - function getActiveFileContext(): ActiveFile | undefined { - return activeFileContext; + function getOpenFilesContext(): OpenFiles | undefined { + return openFilesContext; } /** @@ -101,7 +101,7 @@ export function createIdeContextStore() { * @param subscriber The function to be called when the active file context changes. * @returns A function that, when called, will unsubscribe the provided subscriber. */ - function subscribeToActiveFile(subscriber: ActiveFileSubscriber): () => void { + function subscribeToOpenFiles(subscriber: OpenFilesSubscriber): () => void { subscribers.add(subscriber); return () => { subscribers.delete(subscriber); @@ -109,10 +109,10 @@ export function createIdeContextStore() { } return { - setActiveFileContext, - getActiveFileContext, - subscribeToActiveFile, - clearActiveFileContext, + setOpenFilesContext, + getOpenFilesContext, + subscribeToOpenFiles, + clearOpenFilesContext, }; } |
