Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 3d512de

Browse files
authored
Merge pull request #610 from codestoryai/features/add-go-to-implementation-support
[sidecar] add go-to-implementation support
2 parents c58023c + 0038d6f commit 3d512de

File tree

5 files changed

+134
-61
lines changed

5 files changed

+134
-61
lines changed

extensions/codestory/src/extension.ts

+38-52
Original file line numberDiff line numberDiff line change
@@ -32,41 +32,12 @@ import { AideQuickFix } from './quickActions/fix';
3232
import { copySettings } from './utilities/copySettings';
3333

3434

35+
export let SIDECAR_CLIENT: SideCarClient | null = null;
36+
37+
3538

3639
export async function activate(context: ExtensionContext) {
3740
// Project root here
38-
// start a stupid server here
39-
const server = http.createServer(handleRequest);
40-
let port = 42423; // Default chooses 42423, but if its not available then we
41-
// can still grab it by listenting to port 0
42-
server.listen(port, () => {
43-
console.log(`Server for talking to sidecar is running at http://localhost:${port}/`);
44-
})
45-
.on('error', (err: NodeJS.ErrnoException) => {
46-
if (err.code === 'EADDRINUSE') {
47-
console.error(`Port ${port} is already in use, trying another port...`);
48-
server.listen(0, () => {
49-
const serverAddress = server.address();
50-
if (serverAddress) {
51-
const newAddress: AddressInfo = serverAddress as AddressInfo;
52-
port = newAddress.port;
53-
}
54-
console.log(serverAddress);
55-
console.log(`Server for talking to sidecar is running at http://localhost:${server.address()}/`);
56-
}); // Use 0 to let the OS pick an available port
57-
} else {
58-
console.error(`Failed to start server: ${err.message}`);
59-
}
60-
});
61-
62-
// Register a disposable to stop the server when the extension is deactivated
63-
context.subscriptions.push({
64-
dispose: () => {
65-
if (server) {
66-
server.close();
67-
}
68-
},
69-
});
7041
const uniqueUserId = getUniqueId();
7142
const userId = getUserId();
7243
console.log('User id:' + userId);
@@ -166,6 +137,41 @@ export async function activate(context: ExtensionContext) {
166137
// allow-any-unicode-next-line
167138
// window.showInformationMessage(`Sidecar binary 🦀 started at ${sidecarUrl}`);
168139
const sidecarClient = new SideCarClient(sidecarUrl, modelConfiguration);
140+
SIDECAR_CLIENT = sidecarClient;
141+
142+
// Server for the sidecar to talk to the editor
143+
const server = http.createServer(handleRequest);
144+
let port = 42423; // Default chooses 42423, but if its not available then we
145+
// can still grab it by listenting to port 0
146+
server.listen(port, () => {
147+
console.log(`Server for talking to sidecar is running at http://localhost:${port}/`);
148+
})
149+
.on('error', (err: NodeJS.ErrnoException) => {
150+
if (err.code === 'EADDRINUSE') {
151+
console.error(`Port ${port} is already in use, trying another port...`);
152+
server.listen(0, () => {
153+
const serverAddress = server.address();
154+
if (serverAddress) {
155+
const newAddress: AddressInfo = serverAddress as AddressInfo;
156+
port = newAddress.port;
157+
}
158+
console.log(serverAddress);
159+
console.log(`Server for talking to sidecar is running at http://localhost:${server.address()}/`);
160+
}); // Use 0 to let the OS pick an available port
161+
} else {
162+
console.error(`Failed to start server: ${err.message}`);
163+
}
164+
});
165+
166+
// Register a disposable to stop the server when the extension is deactivated
167+
context.subscriptions.push({
168+
dispose: () => {
169+
if (server) {
170+
server.close();
171+
}
172+
},
173+
});
174+
169175
// we want to send the open tabs here to the sidecar
170176
const openTextDocuments = await getRelevantFiles();
171177
openTextDocuments.forEach((openTextDocument) => {
@@ -254,26 +260,6 @@ export async function activate(context: ExtensionContext) {
254260
);
255261
context.subscriptions.push(chatAgentProvider);
256262

257-
// Also track the documents when they were last opened
258-
// context.subscriptions.push(
259-
// workspace.onDidOpenTextDocument(async (doc) => {
260-
// const uri = doc.uri;
261-
// console.log('document open');
262-
// // TODO(skcd): we want to send the file open event to the sidecar client
263-
// if (shouldTrackFile(uri)) {
264-
// console.log('we are tracking uri', uri.scheme);
265-
// await sidecarClient.documentOpen(uri.fsPath, doc.getText(), doc.languageId);
266-
// }
267-
// });
268-
269-
// // Listen for active editor change events (user navigating between files)
270-
// window.onDidChangeActiveTextEditor(async (editor) => {
271-
// activeFilesTracker.onDidChangeActiveTextEditor(editor);
272-
// // if we are going to change the active text editor, then we should tell
273-
// // the sidecar about it
274-
// await changedActiveDocument(editor, sidecarClient);
275-
// });
276-
277263
// Register feedback commands
278264
context.subscriptions.push(
279265
commands.registerCommand('codestory.feedback', async () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { SidecarGoToImplementationRequest, SidecarGoToImplementationResponse } from './types';
8+
import { shouldTrackFile } from '../utilities/openTabs';
9+
10+
11+
export async function goToImplementation(request: SidecarGoToImplementationRequest): Promise<SidecarGoToImplementationResponse> {
12+
const locations: vscode.LocationLink[] = await vscode.commands.executeCommand(
13+
'vscode.executeImplementationProvider',
14+
request.fs_file_path,
15+
request.position,
16+
);
17+
const implementations = await Promise.all(locations.map(async (location) => {
18+
const uri = location.targetUri;
19+
const range = location.targetRange;
20+
if (shouldTrackFile(uri)) {
21+
console.log('we are trakcing this uri');
22+
console.log(uri);
23+
}
24+
return {
25+
fs_file_path: uri.fsPath,
26+
range: {
27+
startPosition: {
28+
line: range.start.line,
29+
character: range.start.character,
30+
},
31+
endPosition: {
32+
line: range.end.line,
33+
character: range.end.character,
34+
},
35+
}
36+
};
37+
}));
38+
return {
39+
implementation_locations: implementations,
40+
};
41+
}

extensions/codestory/src/server/openFile.ts

+21-7
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,25 @@ import { SidecarOpenFileToolRequest, SidecarOpenFileToolResponse } from './types
88

99
export async function openFileEditor(request: SidecarOpenFileToolRequest): Promise<SidecarOpenFileToolResponse> {
1010
const filePath = request.fs_file_path;
11-
const textDocument = await vscode.workspace.openTextDocument(filePath);
12-
// we get back the text document over here
13-
const contents = textDocument.getText();
14-
return {
15-
fs_file_path: filePath,
16-
file_contents: contents,
17-
};
11+
try {
12+
const stat = await vscode.workspace.fs.stat(vscode.Uri.file(filePath));
13+
console.log(stat);
14+
const textDocument = await vscode.workspace.openTextDocument(filePath);
15+
// we get back the text document over here
16+
const contents = textDocument.getText();
17+
const language = textDocument.languageId;
18+
return {
19+
fs_file_path: filePath,
20+
file_contents: contents,
21+
language,
22+
exists: true,
23+
};
24+
} catch {
25+
return {
26+
fs_file_path: filePath,
27+
file_contents: '',
28+
language: '',
29+
exists: false,
30+
};
31+
}
1832
}

extensions/codestory/src/server/requestHandler.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55
import * as http from 'http';
6-
import { SidecarDiagnosticsRequest, SidecarGoToDefinitionRequest, SidecarOpenFileToolRequest } from './types';
6+
import { SidecarDiagnosticsRequest, SidecarGoToDefinitionRequest, SidecarGoToImplementationRequest, SidecarOpenFileToolRequest } from './types';
77
import { Position, Range } from 'vscode';
88
import { getDiagnosticsFromEditor } from './diagnostics';
99
import { openFileEditor } from './openFile';
1010
import { goToDefinition } from './goToDefinition';
11+
import { SIDECAR_CLIENT } from '../extension';
12+
import { goToImplementation } from './goToImplementation';
1113

1214
// Helper function to read the request body
1315
function readRequestBody(req: http.IncomingMessage): Promise<string> {
@@ -45,17 +47,33 @@ export async function handleRequest(req: http.IncomingMessage, res: http.ServerR
4547
res.end(JSON.stringify(response));
4648
} else if (req.method === 'POST' && req.url === '/file_open') {
4749
const body = await readRequestBody(req);
50+
console.log('file open request');
4851
const openFileRequest: SidecarOpenFileToolRequest = JSON.parse(body);
4952
const response = await openFileEditor(openFileRequest);
53+
console.log('file open respnose');
54+
console.log(response);
55+
if (response.exists) {
56+
// we should only do this if there is some file content
57+
SIDECAR_CLIENT?.documentOpen(openFileRequest.fs_file_path, response.file_contents, response.language);
58+
}
5059
res.writeHead(200, { 'Content-Type': 'application/json' });
5160
res.end(JSON.stringify(response));
52-
} else if (req.method === 'POST' && req.url === 'go_to_definition') {
61+
} else if (req.method === 'POST' && req.url === '/go_to_definition') {
62+
console.log('go-to-definition');
5363
const body = await readRequestBody(req);
5464
const request: SidecarGoToDefinitionRequest = JSON.parse(body);
5565
const response = await goToDefinition(request);
5666
res.writeHead(200, { 'Content-Type': 'application/json' });
5767
res.end(JSON.stringify(response));
68+
} else if (req.method === 'POST' && req.url === '/go_to_implementation') {
69+
console.log('go-to-implementation');
70+
const body = await readRequestBody(req);
71+
const request: SidecarGoToImplementationRequest = JSON.parse(body);
72+
const response = await goToImplementation(request);
73+
res.writeHead(200, { 'Content-Type': 'application/json' });
74+
res.end(JSON.stringify(response));
5875
} else {
76+
console.log('HC request');
5977
res.writeHead(200, { 'Content-Type': 'application/json' });
6078
res.end(JSON.stringify({ reply: 'gg' }));
6179
}

extensions/codestory/src/server/types.ts

+14
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,18 @@ export type SidecarOpenFileToolRequest = {
5252
export type SidecarOpenFileToolResponse = {
5353
fs_file_path: string;
5454
file_contents: string;
55+
language: string;
56+
exists: boolean;
57+
};
58+
59+
export type SidecarGoToImplementationRequest = {
60+
fs_file_path: string;
61+
position: {
62+
line: number;
63+
character: number;
64+
};
65+
};
66+
67+
export type SidecarGoToImplementationResponse = {
68+
implementation_locations: FileAndRange[];
5569
};

0 commit comments

Comments
 (0)