import React, { useEffect, useMemo, useState } from 'react'; import { Icon } from '@opensumi/ide-components/lib/icon/icon'; import { CommandService, LabelService, URI, path, useInjectable } from '@opensumi/ide-core-browser'; import { WorkbenchEditorService } from '@opensumi/ide-editor'; import { IWorkspaceService } from '@opensumi/ide-workspace'; import { IChatInternalService } from '../../../../common'; import { ChatInternalService } from '../../../chat/chat.internal.service'; import styles from './index.module.less'; interface FileInfo { uri: string; isDirectory: boolean; } interface ExpandableFileListProps { args: any; toolCallId: string; messageId: string; toolName: string; headerText?: string; } export const FileSearchToolComponent: React.FC = ({ args, toolCallId, messageId }) => ( ); export const GrepSearchToolComponent: React.FC = ({ args, toolCallId, messageId }) => ( ); export const ListDirToolComponent: React.FC = ({ args, toolCallId, messageId }) => ( ); const ExpandableFileList: React.FC = ({ args, toolCallId, toolName, messageId, headerText, }) => { const [isExpanded, setIsExpanded] = useState(false); const labelService = useInjectable(LabelService); const editorService = useInjectable(WorkbenchEditorService); const workspaceService = useInjectable(IWorkspaceService); const commandService = useInjectable(CommandService); const workspaceRoot = useMemo(() => URI.parse(workspaceService.tryGetRoots()?.[0]?.uri), []); const chatService = useInjectable(IChatInternalService); const [fileList, setFileList] = useState([]); useEffect(() => { const toDispose = chatService.sessionModel.history.onMessageAdditionalChange((additional) => { if (additional[toolCallId]) { setFileList(additional[toolCallId].files || []); } }); return () => { toDispose.dispose(); }; }, []); const handleFileClick = async (fileInfo: FileInfo) => { // 处理文件点击跳转 if (!fileInfo.isDirectory) { editorService.open(URI.parse(fileInfo.uri)); } else { // 如果是目录,聚焦到文件树并展开该目录 const uri = URI.parse(fileInfo.uri); commandService.executeCommand('filetree.location', uri); } }; const parsedFiles = useMemo( () => fileList.map((file) => { const uri = URI.parse(file.uri); const iconClass = labelService.getIcon(uri, { isDirectory: file.isDirectory }); return { iconClass, name: uri.path.base, path: path.relative(workspaceRoot.codeUri.fsPath, uri.path.dir.toString()), uri: file.uri, isDirectory: file.isDirectory, }; }), [fileList], ); return (
setIsExpanded(!isExpanded)}> {headerText} · {fileList.length} files
{isExpanded && (
    {parsedFiles.map((file, index) => (
  • handleFileClick({ uri: file.uri, isDirectory: file.isDirectory })} > {file.name} {file.path}
  • ))}
)}
); };