diff --git a/src-tauri/src/commands/filesystem.rs b/src-tauri/src/commands/filesystem.rs index bd4ab7b..664814f 100644 --- a/src-tauri/src/commands/filesystem.rs +++ b/src-tauri/src/commands/filesystem.rs @@ -283,7 +283,8 @@ pub async fn get_file_tree(project_path: String) -> Result, String String::from(".DS_Store"), ]; - let root_node = read_directory_recursive(path, 0, 3, &ignore_patterns) + // 增加最大深度为 10,以支持更深的文件夹结构 + let root_node = read_directory_recursive(path, 0, 10, &ignore_patterns) .map_err(|e| e.to_string())?; // Return children of root node if it has any diff --git a/src/components/FileEditorEnhanced.tsx b/src/components/FileEditorEnhanced.tsx index 4536255..a228898 100644 --- a/src/components/FileEditorEnhanced.tsx +++ b/src/components/FileEditorEnhanced.tsx @@ -151,12 +151,13 @@ export const FileEditorEnhanced: React.FC = ({ const [isFullscreen, setIsFullscreen] = useState(false); const [diagnostics, setDiagnostics] = useState([]); const [showDiagnostics, setShowDiagnostics] = useState(true); - const [theme, setTheme] = useState<'vs-dark-plus' | 'vs-dark' | 'vs' | 'hc-black'>('vs-dark-plus'); + const [theme, setTheme] = useState<'vs-dark' | 'vs' | 'hc-black'>('vs-dark'); const [fontSize, setFontSize] = useState(14); const [minimap, setMinimap] = useState(true); const [wordWrap, setWordWrap] = useState<'on' | 'off'>('on'); const [autoSave, setAutoSave] = useState(false); + const [cursorPosition, setCursorPosition] = useState({ line: 1, column: 1 }); const editorRef = useRef(null); const monacoRef = useRef(null); const autoSaveTimerRef = useRef(null); @@ -296,6 +297,14 @@ export const FileEditorEnhanced: React.FC = ({ editorRef.current = editor; monacoRef.current = monaco; + // 监听光标位置变化 + editor.onDidChangeCursorPosition((e) => { + setCursorPosition({ + line: e.position.lineNumber, + column: e.position.column + }); + }); + // 初始化 Monaco 配置 initializeMonaco(); @@ -467,6 +476,79 @@ export const FileEditorEnhanced: React.FC = ({ + {/* 功能信息按钮 */} + + + + + + +
+
+

🎨 语法高亮支持

+

+ JavaScript, TypeScript, Python, Java, C++, C#, Go, Rust, Ruby, PHP, Swift, Kotlin, Dart, Scala, R, MATLAB, SQL, HTML, CSS, JSON, XML, YAML, Markdown 等 40+ 语言 +

+
+ +
+

🔧 代码格式化

+

+ 快捷键: Ctrl/Cmd + Shift + F
+ 支持: JS/TS (Prettier), Python (Black), Java, C/C++, Go (gofmt), Rust (rustfmt), HTML/CSS/JSON +

+
+ +
+

💡 智能提示

+

+ • 代码补全 (IntelliSense)
+ • 参数提示
+ • 悬浮文档
+ • 快速修复建议
+ • 重构建议 +

+
+ +
+

🔍 错误检查

+

+ 实时语法检查、类型检查 (TypeScript/Flow)、Linting (ESLint/TSLint) +

+
+ +
+

⚙️ 编辑器功能

+

+ • 行号显示
+ • 代码折叠
+ • 括号匹配高亮
+ • 多光标编辑
+ • 列选择 (Alt + 鼠标)
+ • 小地图导航
+ • Sticky Scroll (固定显示上下文) +

+
+ +
+

⌨️ 快捷键

+

+ Ctrl/Cmd + S: 保存
+ Ctrl/Cmd + Shift + F: 格式化
+ Ctrl/Cmd + F: 查找
+ Ctrl/Cmd + H: 替换
+ Ctrl/Cmd + /: 注释
+ F11: 全屏
+ Alt + Shift + F: 格式化选中代码 +

+
+
+
+
+
+ {/* 设置菜单 */} @@ -475,9 +557,6 @@ export const FileEditorEnhanced: React.FC = ({ - setTheme('vs-dark-plus')}> - 主题: VS Dark+ - setTheme('vs-dark')}> 主题: VS Dark @@ -624,8 +703,10 @@ export const FileEditorEnhanced: React.FC = ({ options={{ fontSize: fontSize, minimap: { enabled: minimap }, - lineNumbers: "on", - rulers: [80, 120], + lineNumbers: "on", // 显示行号 + lineNumbersMinChars: 5, // 行号最小宽度,增加到 5 以确保显示 + renderLineHighlight: "all", // 高亮当前行 + glyphMargin: true, // 显示字形边距(用于断点等) wordWrap: wordWrap, scrollBeyondLastLine: false, automaticLayout: true, @@ -660,6 +741,7 @@ export const FileEditorEnhanced: React.FC = ({
{language.toUpperCase()} UTF-8 + 行 {cursorPosition.line}, 列 {cursorPosition.column} LF
diff --git a/src/components/FileExplorerPanelEnhanced.tsx b/src/components/FileExplorerPanelEnhanced.tsx index 5d5e157..a38a18e 100644 --- a/src/components/FileExplorerPanelEnhanced.tsx +++ b/src/components/FileExplorerPanelEnhanced.tsx @@ -102,11 +102,14 @@ const getFileIcon = (filename: string) => { return iconMap[ext || ""] || ; }; -// 组织文件到文件夹结构 +// 组织文件到文件夹结构(改进版,支持更深层级) const organizeFilesByFolder = (files: FileNode[]): Map => { const folderMap = new Map(); - const processNode = (node: FileNode, parentPath: string = "") => { + const processNode = (node: FileNode, parentPath: string = "", depth: number = 0) => { + // 限制最大深度为 10 层 + if (depth > 10) return; + const currentPath = parentPath || "根目录"; if (node.file_type === "file") { @@ -116,17 +119,18 @@ const organizeFilesByFolder = (files: FileNode[]): Map => { folderMap.get(currentPath)!.push(node); } else { const folderPath = parentPath ? `${parentPath}/${node.name}` : node.name; + // 创建文件夹条目,即使它没有直接包含文件 if (!folderMap.has(folderPath)) { folderMap.set(folderPath, []); } - if (node.children) { - node.children.forEach(child => processNode(child, folderPath)); + if (node.children && node.children.length > 0) { + node.children.forEach(child => processNode(child, folderPath, depth + 1)); } } }; - files.forEach(node => processNode(node)); + files.forEach(node => processNode(node, "", 0)); return folderMap; }; @@ -318,11 +322,8 @@ export const FileExplorerPanelEnhanced: React.FC setFileTree(tree); setFilteredTree(tree); - // 默认展开第一层目录 - const firstLevelDirs = tree - .filter(node => node.file_type === 'directory') - .map(node => node.path); - setExpandedNodes(new Set(firstLevelDirs)); + // 不默认展开任何目录,让用户手动展开或使用展开按钮 + setExpandedNodes(new Set()); } catch (err) { console.error("Failed to load file tree:", err); setError(err instanceof Error ? err.message : "Failed to load file tree"); @@ -492,11 +493,12 @@ export const FileExplorerPanelEnhanced: React.FC } }, [onFileSelect, toggleExpand, lastClickTime, lastClickPath, handleOpenFile]); - // 渲染文件节点 + // 渲染文件节点(优化深层目录显示) const renderFileNode = (node: FileNode, depth = 0) => { const isExpanded = expandedNodes.has(node.path); const isSelected = selectedPath === node.path; const isDirectory = node.file_type === 'directory'; + const hasChildren = node.children && node.children.length > 0; // 计算显示的路径(处理长路径) const displayName = node.name.length > 30 @@ -513,10 +515,10 @@ export const FileExplorerPanelEnhanced: React.FC isSelected && "bg-accent", "select-none" )} - style={{ paddingLeft: `${depth * 16 + 8}px` }} + style={{ paddingLeft: `${Math.min(depth * 16 + 8, 200)}px` }} // 限制最大缩进 onClick={() => handleFileClick(node)} > - {isDirectory && ( + {isDirectory && hasChildren && (
{isExpanded ? ( @@ -525,6 +527,9 @@ export const FileExplorerPanelEnhanced: React.FC )}
)} + {isDirectory && !hasChildren && ( +
// 空文件夹的占位符 + )} {isDirectory ? ( isExpanded ? ( diff --git a/src/components/GitPanelEnhanced.tsx b/src/components/GitPanelEnhanced.tsx index 7044383..9b29dcc 100644 --- a/src/components/GitPanelEnhanced.tsx +++ b/src/components/GitPanelEnhanced.tsx @@ -449,7 +449,7 @@ export const GitPanelEnhanced: React.FC = ({ }, [gitStatus]); - // 渲染文件树节点 + // 渲染文件树节点(优化深层目录显示) const renderFileTreeNode = (node: FileTreeNode, depth = 0, statusType: 'modified' | 'staged' | 'untracked' | 'conflicted') => { const isExpanded = node.type === 'directory' && expandedNodes.has(node.path); const isDirectory = node.type === 'directory'; @@ -463,7 +463,7 @@ export const GitPanelEnhanced: React.FC = ({ "flex items-center gap-1 px-2 py-1 hover:bg-accent rounded-sm cursor-pointer group", isSelected && "bg-accent" )} - style={{ paddingLeft: `${depth * 16 + 8}px` }} + style={{ paddingLeft: `${Math.min(depth * 16 + 8, 200)}px` }} // 限制最大缩进 onClick={() => { setSelectedPath(node.path); if (isDirectory) { @@ -482,6 +482,9 @@ export const GitPanelEnhanced: React.FC = ({ )}
)} + {isDirectory && !hasChildren && ( +
// 空文件夹的占位符 + )} {isDirectory ? ( isExpanded ? (