From 70a195547d05a94a478cdb3b9130af02819f87d7 Mon Sep 17 00:00:00 2001 From: Sma1lboy <541898146chen@gmail.com> Date: Wed, 29 Jan 2025 13:22:06 -0600 Subject: [PATCH 1/2] feat(api): add listActiveSymbols method to retrieve active symbols in the editor --- clients/tabby-chat-panel/src/index.ts | 10 ++++ clients/vscode/src/chat/createClient.ts | 1 + clients/vscode/src/chat/webview.ts | 65 +++++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/clients/tabby-chat-panel/src/index.ts b/clients/tabby-chat-panel/src/index.ts index b2d4bdbe3345..3d44cbb1fc6f 100644 --- a/clients/tabby-chat-panel/src/index.ts +++ b/clients/tabby-chat-panel/src/index.ts @@ -252,6 +252,13 @@ export interface ListFileItem { filepath: Filepath } +// Draft list active symbol item +export interface ListActiveSymbolItem { + filepath: Filepath + range: LineRange + label: string +} + export interface ServerApi { init: (request: InitRequest) => void @@ -344,6 +351,8 @@ export interface ClientApiMethods { */ listFileInWorkspace?: (params: ListFilesInWorkspaceParams) => Promise + listActiveSymbols?: () => Promise + /** * Returns the content of a file within the specified range. * If `range` is not provided, the entire file content is returned. @@ -351,6 +360,7 @@ export interface ClientApiMethods { * @returns The content of the file as a string, or `null` if the file or range cannot be accessed. */ readFileContent?: (info: FileRange) => Promise + } export interface ClientApi extends ClientApiMethods { diff --git a/clients/vscode/src/chat/createClient.ts b/clients/vscode/src/chat/createClient.ts index a962a5637f45..ede31e7a02b4 100644 --- a/clients/vscode/src/chat/createClient.ts +++ b/clients/vscode/src/chat/createClient.ts @@ -40,6 +40,7 @@ export function createClient(webview: Webview, api: ClientApiMethods): ServerApi storeSessionState: api.storeSessionState, listFileInWorkspace: api.listFileInWorkspace, readFileContent: api.readFileContent, + listActiveSymbols: api.listActiveSymbols, }, }); } diff --git a/clients/vscode/src/chat/webview.ts b/clients/vscode/src/chat/webview.ts index 3cb76cc908bd..0fddc1ec8943 100644 --- a/clients/vscode/src/chat/webview.ts +++ b/clients/vscode/src/chat/webview.ts @@ -15,6 +15,9 @@ import { Location, LocationLink, TabInputText, + SymbolInformation, + DocumentSymbol, + SymbolKind, } from "vscode"; import { TABBY_CHAT_PANEL_API_VERSION } from "tabby-chat-panel"; import type { @@ -30,6 +33,7 @@ import type { ListFilesInWorkspaceParams, ListFileItem, FileRange, + ListActiveSymbolItem, } from "tabby-chat-panel"; import * as semver from "semver"; import debounce from "debounce"; @@ -550,6 +554,67 @@ export class ChatWebview { const document = await workspace.openTextDocument(uri); return document.getText(chatPanelLocationToVSCodeRange(info.range) ?? undefined); }, + listActiveSymbols: async (): Promise => { + const editor = window.activeTextEditor; + if (!editor) { + return []; + } + + try { + const symbols = + ((await commands.executeCommand("vscode.executeDocumentSymbolProvider", editor.document.uri)) as ( + | SymbolInformation + | DocumentSymbol + )[]) || []; + + // FIXME: remove this + this.logger.info(`Fetched symbols: ${symbols?.length}`); + this.logger.info("Symbols:", symbols); + // TODO: put this into utils + const includesSymbolList = [ + SymbolKind.Function, + SymbolKind.Struct, + SymbolKind.Interface, + SymbolKind.Class, + SymbolKind.Method, + SymbolKind.Module, + ]; + + const collectFunctions = (symbols: (SymbolInformation | DocumentSymbol)[]): SymbolInformation[] => { + const result: SymbolInformation[] = []; + + for (const symbol of symbols) { + if (symbol instanceof DocumentSymbol) { + if (includesSymbolList.includes(symbol.kind)) { + result.push( + new SymbolInformation( + symbol.name, + symbol.kind, + symbol.detail, + new Location(editor.document.uri, symbol.range), + ), + ); + } + if (symbol.children?.length) { + result.push(...collectFunctions(symbol.children)); + } + } else if (includesSymbolList.includes(symbol.kind)) { + result.push(symbol); + } + } + return result; + }; + const filepath = localUriToChatPanelFilepath(editor.document.uri, this.gitProvider); + return collectFunctions(symbols || []).map((symbol) => ({ + filepath, + range: { start: symbol.location.range.start.line + 1, end: symbol.location.range.end.line + 1 }, + label: symbol.name, + })); + } catch (error) { + this.logger.error(`Failed to fetch symbols: ${error}`); + return []; + } + }, }); } From 31c6e391627247c9e1df56be754ccf3635da0239 Mon Sep 17 00:00:00 2001 From: Sma1lboy <541898146chen@gmail.com> Date: Wed, 29 Jan 2025 13:59:31 -0600 Subject: [PATCH 2/2] feat(chat): add vscodeRangeToChatPanelLineRange utility function for range conversion --- clients/vscode/src/chat/utils.ts | 7 +++++++ clients/vscode/src/chat/webview.ts | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/clients/vscode/src/chat/utils.ts b/clients/vscode/src/chat/utils.ts index 108cb929baa1..055a6dae0ae2 100644 --- a/clients/vscode/src/chat/utils.ts +++ b/clients/vscode/src/chat/utils.ts @@ -121,6 +121,13 @@ export function chatPanelLineRangeToVSCodeRange(lineRange: LineRange): VSCodeRan return new VSCodeRange(Math.max(0, lineRange.start - 1), 0, lineRange.end, 0); } +export function vscodeRangeToChatPanelLineRange(range: VSCodeRange): LineRange { + return { + start: range.start.line + 1, + end: range.end.line + 1, + }; +} + export function chatPanelLocationToVSCodeRange(location: Location | undefined): VSCodeRange | null { if (!location) { return null; diff --git a/clients/vscode/src/chat/webview.ts b/clients/vscode/src/chat/webview.ts index 0fddc1ec8943..080db7ba6909 100644 --- a/clients/vscode/src/chat/webview.ts +++ b/clients/vscode/src/chat/webview.ts @@ -54,6 +54,7 @@ import { isValidForSyncActiveEditorSelection, localUriToListFileItem, escapeGlobPattern, + vscodeRangeToChatPanelLineRange, } from "./utils"; import { findFiles } from "../findFiles"; import mainHtml from "./html/main.html"; @@ -607,7 +608,7 @@ export class ChatWebview { const filepath = localUriToChatPanelFilepath(editor.document.uri, this.gitProvider); return collectFunctions(symbols || []).map((symbol) => ({ filepath, - range: { start: symbol.location.range.start.line + 1, end: symbol.location.range.end.line + 1 }, + range: vscodeRangeToChatPanelLineRange(symbol.location.range), label: symbol.name, })); } catch (error) {