From 5e7232f1d03848db71007f89e41a3d53651ab193 Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 01:41:03 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E5=AE=8C=E6=88=90=EF=BC=81=E6=80=BB?= =?UTF-8?q?=E7=BB=93=E4=B8=80=E4=B8=8B=E6=89=80=E5=81=9A=E7=9A=84=E6=94=B9?= =?UTF-8?q?=E5=8A=A8=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 完成内容 ### 1. 添加了新测试用例 在 `packages/rspress-plugin-file-tree/tests/parser.spec.ts` 中添加了: - 在 `Should parse input with spaces` 测试中增加了 2-space 缩进格式的验证 - 新增 `Should parse 2-space and 4-space indentation identically` 测试,验证两种缩进格式产生相同结果 ### 2. 修复了 tree-parser 在 `packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts` 的 `calculateIndent` 函数中: - 添加了对 `│ ` (2-char) 缩进模式的支持 - 添加了对 ` ` (2 spaces) 缩进模式的支持 - 保持了对原有 4-char 缩进模式的兼容 现在两种格式都能正确解析为相同的树结构: ``` │ ├── (4-space) │ ├── (2-space) ``` --- .../src/components/tree-parser/tree-parser.ts | 19 ++- .../tests/parser.spec.ts | 119 ++++++++++++++++++ 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts index 3e28ce8..3f35b23 100644 --- a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts +++ b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts @@ -56,7 +56,7 @@ export function parseTreeContent(content: string): ParsedTree { /** * Calculate indent level from line - * Each level is typically 4 characters: "│ " or " " + * Supports both 4-character ("│ ") and 2-character ("│ ") indent patterns */ function calculateIndent(line: string): number { let indent = 0; @@ -65,13 +65,21 @@ function calculateIndent(line: string): number { while (i < line.length) { const char = line[i]; - // Check for "│ " pattern (vertical line + 3 spaces) + // Check for "│ " pattern (vertical line + 3 spaces) - 4-char indent if (char === '│' && line.substring(i, i + 4) === '│ ') { indent++; i += 4; continue; } + // Check for "│ " pattern (vertical line + 1 space) - 2-char indent + // Must check this AFTER 4-char to avoid partial matches + if (char === '│' && line[i + 1] === ' ') { + indent++; + i += 2; + continue; + } + // Check for 4 spaces if (line.substring(i, i + 4) === ' ') { indent++; @@ -79,6 +87,13 @@ function calculateIndent(line: string): number { continue; } + // Check for 2 spaces (must come after 4-space check) + if (line.substring(i, i + 2) === ' ') { + indent++; + i += 2; + continue; + } + // Check for branch characters (├── or └──) if (char === '├' || char === '└') { if ( diff --git a/packages/rspress-plugin-file-tree/tests/parser.spec.ts b/packages/rspress-plugin-file-tree/tests/parser.spec.ts index a380006..20114d6 100644 --- a/packages/rspress-plugin-file-tree/tests/parser.spec.ts +++ b/packages/rspress-plugin-file-tree/tests/parser.spec.ts @@ -349,6 +349,31 @@ test('Should parse input with spaces', () => { │ ├── index.ts │ └── parser.ts // Parse string input to tree structure └── 1. tsconfig.json +`; + + // Alternative format with 2-space indentation (should produce same result) + const input2SpaceIndent = ` +├── 0. rspress.config.ts // Rspress config +├── -1. src +│ ├── 2. components // Shared components +│ │ ├── FileTreeRender.tsx // The file tree render entry +│ │ ├── Tree +│ │ │ ├── Expand.tsx +│ │ │ ├── FileIcon.tsx +│ │ │ ├── Tree.tsx +│ │ │ ├── TreeContext.tsx +│ │ │ ├── TreeFile.tsx +│ │ │ ├── TreeFolder.tsx +│ │ │ ├── TreeFolderIcon.tsx +│ │ │ ├── TreeIndents.tsx +│ │ │ ├── TreeStatusIcon.tsx +│ │ │ ├── index.less +│ │ │ └── index.tsx +│ │ ├── helpers.ts +│ │ └── presets.ts +│ ├── index.ts +│ └── parser.ts // Parse string input to tree structure +└── 1. tsconfig.json `; expect(parseTreeContent(input).nodes).toMatchInlineSnapshot(` [ @@ -483,4 +508,98 @@ test('Should parse input with spaces', () => { }, ] `); + + // Both formats should produce the same result + expect(parseTreeContent(input2SpaceIndent).nodes).toEqual( + parseTreeContent(input).nodes + ); +}); + +test('Should parse 2-space and 4-space indentation identically', () => { + // 4-space indentation format (standard) + const input4Space = ` +├── docs +│ ├── index.md +│ ├── api +│ │ ├── index.md +│ │ ├── theme +│ │ │ ├── index.md +│ │ │ ├── component.mdx +│ │ │ ├── utils.mdx +`; + + // 2-space indentation format (alternative) + const input2Space = ` +├── docs +│ ├── index.md +│ ├── api +│ │ ├── index.md +│ │ ├── theme +│ │ │ ├── index.md +│ │ │ ├── component.mdx +│ │ │ ├── utils.mdx +`; + + const result4Space = parseTreeContent(input4Space).nodes; + const result2Space = parseTreeContent(input2Space).nodes; + + // Both should produce identical results + expect(result2Space).toEqual(result4Space); + + // Verify the structure is correct + expect(result4Space).toMatchInlineSnapshot(` + [ + { + "children": [ + { + "children": [], + "extension": "md", + "name": "index.md", + "type": "file", + }, + { + "children": [ + { + "children": [], + "extension": "md", + "name": "index.md", + "type": "file", + }, + { + "children": [ + { + "children": [], + "extension": "md", + "name": "index.md", + "type": "file", + }, + { + "children": [], + "extension": "mdx", + "name": "component.mdx", + "type": "file", + }, + { + "children": [], + "extension": "mdx", + "name": "utils.mdx", + "type": "file", + }, + ], + "extension": undefined, + "name": "theme", + "type": "directory", + }, + ], + "extension": undefined, + "name": "api", + "type": "directory", + }, + ], + "extension": undefined, + "name": "docs", + "type": "directory", + }, + ] + `); }); From 9920eeef5259a462fb532fae2e510a3189e9d602 Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 01:46:07 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E5=85=A8=E9=83=A8=E5=AE=8C=E6=88=90?= =?UTF-8?q?=EF=BC=81=E6=80=BB=E7=BB=93=E4=B8=80=E4=B8=8B=E6=89=80=E5=81=9A?= =?UTF-8?q?=E7=9A=84=E6=94=B9=E5=8A=A8=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 完成内容 ### 1. 类型定义更新 `src/components/tree-parser/types.ts`: - 在 `TreeNode` 接口中添加了 `comment?: string` 字段 ### 2. Parser 更新 `src/components/tree-parser/tree-parser.ts`: - 支持 `//` 和 `#` 两种注释格式 - 解析出的注释存储在 `comment` 字段中 ### 3. UI 组件更新 `src/components/FileTree/FileTreeItem.tsx`: - 添加注释显示逻辑 `src/components/FileTree/FileTreeItem.module.less`: - 添加 `.comment` 样式,使用 `var(--rp-c-text-2)` 颜色 ### 4. 新增测试 - `Should parse space-only indentation without tree characters` - 测试纯空格缩进格式 - `Should parse both // and # style comments` - 测试两种注释格式 现在以下格式都能正确解析并显示注释: ``` docs ├── advanced.mdx └── advanced ├── _meta.json # hello world └── utils.ts // hello world2 ``` --- .../FileTree/FileTreeItem.module.less | 9 ++ .../src/components/FileTree/FileTreeItem.tsx | 1 + .../src/components/tree-parser/tree-parser.ts | 10 +- .../src/components/tree-parser/types.ts | 1 + .../tests/parser.spec.ts | 148 ++++++++++++++++++ 5 files changed, 166 insertions(+), 3 deletions(-) diff --git a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.module.less b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.module.less index 0a2e522..c840101 100644 --- a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.module.less +++ b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.module.less @@ -51,6 +51,15 @@ text-overflow: ellipsis; } +.comment { + margin-left: 8px; + color: var(--rp-c-text-2); + font-style: italic; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .children { display: flex; flex-direction: column; diff --git a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx index 7eba987..f3037f6 100644 --- a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx +++ b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx @@ -57,6 +57,7 @@ export const FileTreeItem: React.FC = ({ node, depth }) => { /> {node.name} + {node.comment && {node.comment}} {isDirectory && node.children.length > 0 && expanded && ( diff --git a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts index 3f35b23..2e1cdd8 100644 --- a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts +++ b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts @@ -19,9 +19,12 @@ export function parseTreeContent(content: string): ParsedTree { const indent = calculateIndent(line); const fullName = extractName(line); // Split name and potential comment + // Supports both "//" and "#" style comments // e.g. "file.ts // comment" -> name="file.ts", comment="comment" - const commentMatch = fullName.match(/^(.*?)(?:\s*\/\/\s*(.*))?$/); + // e.g. "file.ts # comment" -> name="file.ts", comment="comment" + const commentMatch = fullName.match(/^(.*?)(?:\s*(?:\/\/|#)\s*(.*))?$/); const name = commentMatch ? commentMatch[1].trim() : fullName; + const comment = commentMatch?.[2]?.trim() || undefined; if (!name) continue; @@ -32,6 +35,7 @@ export function parseTreeContent(content: string): ParsedTree { type: isDirectory ? 'directory' : 'file', children: [], extension: isDirectory ? undefined : getExtension(name), + comment, }; // Find parent node by popping items with equal or greater indent @@ -129,8 +133,8 @@ function extractName(line: string): string { * - Has no extension */ function isDirectoryName(name: string): boolean { - // Strip comments if any (though name passed here usually already has them, let's be safe if logic changes) - const cleanName = name.split(/\s+\/\//)[0].trim(); + // Strip comments if any (supports both // and # comments) + const cleanName = name.split(/\s+(?:\/\/|#)/)[0].trim(); if (cleanName.endsWith('/')) return true; diff --git a/packages/rspress-plugin-file-tree/src/components/tree-parser/types.ts b/packages/rspress-plugin-file-tree/src/components/tree-parser/types.ts index 5d38cdb..eb57f8e 100644 --- a/packages/rspress-plugin-file-tree/src/components/tree-parser/types.ts +++ b/packages/rspress-plugin-file-tree/src/components/tree-parser/types.ts @@ -3,6 +3,7 @@ export interface TreeNode { type: 'file' | 'directory'; children: TreeNode[]; extension?: string; + comment?: string; } export interface ParsedTree { diff --git a/packages/rspress-plugin-file-tree/tests/parser.spec.ts b/packages/rspress-plugin-file-tree/tests/parser.spec.ts index 20114d6..faacac5 100644 --- a/packages/rspress-plugin-file-tree/tests/parser.spec.ts +++ b/packages/rspress-plugin-file-tree/tests/parser.spec.ts @@ -30,12 +30,14 @@ test('Should parse normal input', () => { [ { "children": [], + "comment": undefined, "extension": "", "name": ".", "type": "file", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "rspress.config.ts", "type": "file", @@ -46,6 +48,7 @@ test('Should parse normal input', () => { "children": [ { "children": [], + "comment": undefined, "extension": "tsx", "name": "FileTreeRender.tsx", "type": "file", @@ -54,111 +57,130 @@ test('Should parse normal input', () => { "children": [ { "children": [], + "comment": undefined, "extension": "tsx", "name": "Expand.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "FileIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "Tree.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeContext.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFile.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFolder.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFolderIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeIndents.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeStatusIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "less", "name": "index.less", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "index.tsx", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "Tree", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "helpers.ts", "type": "file", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "presets.ts", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "components", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "index.ts", "type": "file", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "parser.ts", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "src", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "json", "name": "tsconfig.json", "type": "file", @@ -195,6 +217,7 @@ test('Should parse input with comments', () => { [ { "children": [], + "comment": "Rspress config", "extension": "ts", "name": "rspress.config.ts", "type": "file", @@ -205,6 +228,7 @@ test('Should parse input with comments', () => { "children": [ { "children": [], + "comment": "The file tree render entry", "extension": "tsx", "name": "FileTreeRender.tsx", "type": "file", @@ -213,111 +237,130 @@ test('Should parse input with comments', () => { "children": [ { "children": [], + "comment": undefined, "extension": "tsx", "name": "Expand.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "FileIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "Tree.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeContext.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFile.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFolder.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFolderIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeIndents.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeStatusIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "less", "name": "index.less", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "index.tsx", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "Tree", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "helpers.ts", "type": "file", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "presets.ts", "type": "file", }, ], + "comment": "Shared components", "extension": undefined, "name": "components", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "index.ts", "type": "file", }, { "children": [], + "comment": "Parse string input to tree structure", "extension": "ts", "name": "parser.ts", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "src", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "json", "name": "tsconfig.json", "type": "file", @@ -379,6 +422,7 @@ test('Should parse input with spaces', () => { [ { "children": [], + "comment": "Rspress config", "extension": "ts", "name": "0. rspress.config.ts", "type": "file", @@ -389,6 +433,7 @@ test('Should parse input with spaces', () => { "children": [ { "children": [], + "comment": "The file tree render entry", "extension": "tsx", "name": "FileTreeRender.tsx", "type": "file", @@ -397,111 +442,130 @@ test('Should parse input with spaces', () => { "children": [ { "children": [], + "comment": undefined, "extension": "tsx", "name": "Expand.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "FileIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "Tree.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeContext.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFile.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFolder.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeFolderIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeIndents.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "TreeStatusIcon.tsx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "less", "name": "index.less", "type": "file", }, { "children": [], + "comment": undefined, "extension": "tsx", "name": "index.tsx", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "Tree", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "helpers.ts", "type": "file", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "presets.ts", "type": "file", }, ], + "comment": "Shared components", "extension": undefined, "name": "2. components", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "ts", "name": "index.ts", "type": "file", }, { "children": [], + "comment": "Parse string input to tree structure", "extension": "ts", "name": "parser.ts", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "-1. src", "type": "directory", }, { "children": [], + "comment": undefined, "extension": "json", "name": "1. tsconfig.json", "type": "file", @@ -553,6 +617,7 @@ test('Should parse 2-space and 4-space indentation identically', () => { "children": [ { "children": [], + "comment": undefined, "extension": "md", "name": "index.md", "type": "file", @@ -561,6 +626,7 @@ test('Should parse 2-space and 4-space indentation identically', () => { "children": [ { "children": [], + "comment": undefined, "extension": "md", "name": "index.md", "type": "file", @@ -569,33 +635,39 @@ test('Should parse 2-space and 4-space indentation identically', () => { "children": [ { "children": [], + "comment": undefined, "extension": "md", "name": "index.md", "type": "file", }, { "children": [], + "comment": undefined, "extension": "mdx", "name": "component.mdx", "type": "file", }, { "children": [], + "comment": undefined, "extension": "mdx", "name": "utils.mdx", "type": "file", }, ], + "comment": undefined, "extension": undefined, "name": "theme", "type": "directory", }, ], + "comment": undefined, "extension": undefined, "name": "api", "type": "directory", }, ], + "comment": undefined, "extension": undefined, "name": "docs", "type": "directory", @@ -603,3 +675,79 @@ test('Should parse 2-space and 4-space indentation identically', () => { ] `); }); + +test('Should parse space-only indentation without tree characters', () => { + const input = ` +docs +├── advanced.mdx +└── advanced + ├── _meta.json + └── nested +`; + + expect(parseTreeContent(input).nodes).toMatchInlineSnapshot(` + [ + { + "children": [ + { + "children": [], + "comment": undefined, + "extension": "mdx", + "name": "advanced.mdx", + "type": "file", + }, + { + "children": [ + { + "children": [], + "comment": undefined, + "extension": "json", + "name": "_meta.json", + "type": "file", + }, + { + "children": [], + "comment": undefined, + "extension": undefined, + "name": "nested", + "type": "directory", + }, + ], + "comment": undefined, + "extension": undefined, + "name": "advanced", + "type": "directory", + }, + ], + "comment": undefined, + "extension": undefined, + "name": "docs", + "type": "directory", + }, + ] + `); +}); + +test('Should parse both // and # style comments', () => { + const input = ` +docs +├── advanced.mdx +└── advanced + ├── _meta.json # hello world + └── utils.ts // hello world2 +`; + + const result = parseTreeContent(input).nodes; + + // Check that comments are parsed correctly + const advancedDir = result[0].children[1]; + expect(advancedDir.name).toBe('advanced'); + + const metaJson = advancedDir.children[0]; + expect(metaJson.name).toBe('_meta.json'); + expect(metaJson.comment).toBe('hello world'); + + const utilsTs = advancedDir.children[1]; + expect(utilsTs.name).toBe('utils.ts'); + expect(utilsTs.comment).toBe('hello world2'); +}); From 9e9ff454dfd7977b22c564db18f56a246051dedf Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:08:23 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E5=AE=8C=E6=88=90=EF=BC=81=E6=80=BB?= =?UTF-8?q?=E7=BB=93=E4=B8=80=E4=B8=8B=E6=9C=AC=E6=AC=A1=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 完成内容 ### Parser 重构 `src/components/tree-parser/tree-parser.ts`: 1. **新增 `extractNameAndComment` 函数** - 基于文件名规则检测注释: - 使用 2+ 空格作为主要分隔符 - 文件有扩展名时,扩展名后的内容是注释 - 目录名后跟非字母数字开头的内容是注释 - 隐藏文件(以 `.` 开头)后的内容是注释 2. **新增 `isValidName` 函数** - 验证文件/目录名是否合法 3. **移除了特定注释符号的检测** - 不再特判 `//`, `#`, `<--` 等,所有文件名后的内容都完整保留为注释 ### 测试更新 - 更新了快照以反映注释包含完整内容 - 修改了测试期望值:`<-- "@rspress/core/theme"` 现在作为完整注释保留 ### 新行为示例 ``` index.mdx <-- "@rspress/core/theme" ``` - `name`: `index.mdx` - `comment`: `<-- "@rspress/core/theme"`(完整保留) --- .../src/components/tree-parser/tree-parser.ts | 132 +++++++++++++++--- .../tests/parser.spec.ts | 74 ++++++++-- 2 files changed, 178 insertions(+), 28 deletions(-) diff --git a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts index 2e1cdd8..16c7245 100644 --- a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts +++ b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts @@ -18,13 +18,11 @@ export function parseTreeContent(content: string): ParsedTree { for (const line of lines) { const indent = calculateIndent(line); const fullName = extractName(line); - // Split name and potential comment - // Supports both "//" and "#" style comments - // e.g. "file.ts // comment" -> name="file.ts", comment="comment" - // e.g. "file.ts # comment" -> name="file.ts", comment="comment" - const commentMatch = fullName.match(/^(.*?)(?:\s*(?:\/\/|#)\s*(.*))?$/); - const name = commentMatch ? commentMatch[1].trim() : fullName; - const comment = commentMatch?.[2]?.trim() || undefined; + + // Extract name and comment + // Rule: filename ends when we detect a valid file/directory name pattern, + // everything after (with leading spaces) is treated as comment + const { name, comment } = extractNameAndComment(fullName); if (!name) continue; @@ -127,27 +125,127 @@ function extractName(line: string): string { .trim(); } +/** + * Extract filename/dirname and comment from a line + * + * Rules for detecting end of filename: + * 1. Files have extensions: name.ext (e.g., file.ts, config.json) + * 2. Hidden files start with dot: .gitignore, .env + * 3. Directories end with / or have no extension + * 4. Special names: ... (ellipsis for omitted content) + * 5. Everything after the name (separated by 2+ spaces) is comment + * + * Note: Filenames can contain spaces (e.g., "0. file.ts"), so we use + * 2+ consecutive spaces as the delimiter between name and comment. + */ +function extractNameAndComment(fullName: string): { + name: string; + comment: string | undefined; +} { + const trimmed = fullName.trim(); + if (!trimmed) { + return { name: '', comment: undefined }; + } + + // Special case: "..." or similar ellipsis patterns (standalone) + if (/^\.{2,}$/.test(trimmed)) { + return { name: trimmed, comment: undefined }; + } + + // Strategy: Find the last occurrence of a file extension pattern, + // then check if there's content after it (separated by 2+ spaces) + + // First, try to split by 2+ spaces (common comment delimiter) + const doubleSpaceMatch = trimmed.match(/^(.+?)\s{2,}(.+)$/); + if (doubleSpaceMatch) { + const potentialName = doubleSpaceMatch[1].trim(); + const potentialComment = doubleSpaceMatch[2].trim(); + + // Verify the name part looks like a valid file/directory + if (isValidName(potentialName)) { + return { name: potentialName, comment: potentialComment }; + } + } + + // If no double-space delimiter, check if the whole thing is just a name + // For files with extensions or directories, we can be more lenient + // Look for pattern: name.ext followed by single space and non-extension content + const singleSpaceMatch = trimmed.match( + /^(.+?\.[a-zA-Z0-9]+)\s+([^.].*)$/ + ); + if (singleSpaceMatch) { + const potentialName = singleSpaceMatch[1].trim(); + const potentialComment = singleSpaceMatch[2].trim(); + return { name: potentialName, comment: potentialComment }; + } + + // Check for hidden files followed by comment + const hiddenFileMatch = trimmed.match(/^(\.[^\s]+)\s+(.+)$/); + if (hiddenFileMatch) { + return { + name: hiddenFileMatch[1].trim(), + comment: hiddenFileMatch[2].trim(), + }; + } + + // Check for directory name followed by single space and comment + // Directory names don't have extensions, so look for "word space non-word-start" + // Also handles names starting with numbers like "2. components" + const dirCommentMatch = trimmed.match(/^([\w][\w.\s-]*?)\s+([^a-zA-Z0-9].*)$/); + if (dirCommentMatch) { + const potentialName = dirCommentMatch[1].trim(); + // Make sure it's not a file with extension + if (!/\.[a-zA-Z0-9]+$/.test(potentialName)) { + return { + name: potentialName, + comment: dirCommentMatch[2].trim(), + }; + } + } + + // No comment detected, return the whole thing as name + return { name: trimmed, comment: undefined }; +} + +/** + * Check if a string looks like a valid file/directory name + */ +function isValidName(name: string): boolean { + if (!name) return false; + + // Ends with / (explicit directory) + if (name.endsWith('/')) return true; + + // Has a file extension + if (/\.[a-zA-Z0-9]+$/.test(name)) return true; + + // Hidden file/directory (starts with dot) + if (name.startsWith('.')) return true; + + // Looks like a directory name (no extension, word characters) + if (/^[\w\s.-]+$/.test(name)) return true; + + return false; +} + /** * Check if name represents a directory * - Ends with / * - Has no extension */ function isDirectoryName(name: string): boolean { - // Strip comments if any (supports both // and # comments) - const cleanName = name.split(/\s+(?:\/\/|#)/)[0].trim(); + if (name.endsWith('/')) return true; - if (cleanName.endsWith('/')) return true; + const lastPart = name.split('/').pop() || name; - const lastPart = cleanName.split('/').pop() || cleanName; - - // Use a more robust check: files usually have extensions. - // Directories usually don't. - // Exception: Dotfiles (.gitignore) are files. - // exception: names with dots but known extensions are files. + // Special case: ellipsis is not a directory + if (/^\.{2,}$/.test(lastPart)) { + return false; + } // If it starts with a dot, it's a file (hidden file), e.g., .gitignore if (lastPart.startsWith('.')) { - return false; // Treat as file + return false; } // If it has an extension (e.g. foo.ts, bar.config.js), it's a file diff --git a/packages/rspress-plugin-file-tree/tests/parser.spec.ts b/packages/rspress-plugin-file-tree/tests/parser.spec.ts index faacac5..43ed2ab 100644 --- a/packages/rspress-plugin-file-tree/tests/parser.spec.ts +++ b/packages/rspress-plugin-file-tree/tests/parser.spec.ts @@ -217,7 +217,7 @@ test('Should parse input with comments', () => { [ { "children": [], - "comment": "Rspress config", + "comment": "// Rspress config", "extension": "ts", "name": "rspress.config.ts", "type": "file", @@ -228,7 +228,7 @@ test('Should parse input with comments', () => { "children": [ { "children": [], - "comment": "The file tree render entry", + "comment": "// The file tree render entry", "extension": "tsx", "name": "FileTreeRender.tsx", "type": "file", @@ -333,7 +333,7 @@ test('Should parse input with comments', () => { "type": "file", }, ], - "comment": "Shared components", + "comment": "// Shared components", "extension": undefined, "name": "components", "type": "directory", @@ -347,7 +347,7 @@ test('Should parse input with comments', () => { }, { "children": [], - "comment": "Parse string input to tree structure", + "comment": "// Parse string input to tree structure", "extension": "ts", "name": "parser.ts", "type": "file", @@ -422,7 +422,7 @@ test('Should parse input with spaces', () => { [ { "children": [], - "comment": "Rspress config", + "comment": "// Rspress config", "extension": "ts", "name": "0. rspress.config.ts", "type": "file", @@ -433,7 +433,7 @@ test('Should parse input with spaces', () => { "children": [ { "children": [], - "comment": "The file tree render entry", + "comment": "// The file tree render entry", "extension": "tsx", "name": "FileTreeRender.tsx", "type": "file", @@ -538,7 +538,7 @@ test('Should parse input with spaces', () => { "type": "file", }, ], - "comment": "Shared components", + "comment": "// Shared components", "extension": undefined, "name": "2. components", "type": "directory", @@ -552,7 +552,7 @@ test('Should parse input with spaces', () => { }, { "children": [], - "comment": "Parse string input to tree structure", + "comment": "// Parse string input to tree structure", "extension": "ts", "name": "parser.ts", "type": "file", @@ -739,15 +739,67 @@ docs const result = parseTreeContent(input).nodes; - // Check that comments are parsed correctly + // Check that comments are parsed correctly (comments include the markers) const advancedDir = result[0].children[1]; expect(advancedDir.name).toBe('advanced'); const metaJson = advancedDir.children[0]; expect(metaJson.name).toBe('_meta.json'); - expect(metaJson.comment).toBe('hello world'); + expect(metaJson.comment).toBe('# hello world'); const utilsTs = advancedDir.children[1]; expect(utilsTs.name).toBe('utils.ts'); - expect(utilsTs.comment).toBe('hello world2'); + expect(utilsTs.comment).toBe('// hello world2'); +}); + +test('Should parse arrow style comments (<--, -->, <-, ->)', () => { + const input = ` +├── docs +│ └── index.mdx <-- "@rspress/core/theme" +├── theme +│ └── index.tsx <-- "@rspress/core/theme-original" +└── rspress.config.ts +`; + + const result = parseTreeContent(input).nodes; + + // docs/index.mdx - comment includes the arrow + const docsDir = result[0]; + expect(docsDir.name).toBe('docs'); + const indexMdx = docsDir.children[0]; + expect(indexMdx.name).toBe('index.mdx'); + expect(indexMdx.comment).toBe('<-- "@rspress/core/theme"'); + + // theme/index.tsx - comment includes the arrow + const themeDir = result[1]; + expect(themeDir.name).toBe('theme'); + const indexTsx = themeDir.children[0]; + expect(indexTsx.name).toBe('index.tsx'); + expect(indexTsx.comment).toBe('<-- "@rspress/core/theme-original"'); + + // rspress.config.ts (no comment) + const configTs = result[2]; + expect(configTs.name).toBe('rspress.config.ts'); + expect(configTs.comment).toBeUndefined(); +}); + +test('Should treat any text after filename as comment', () => { + const input = ` +├── file1.ts // slash comment +├── file2.ts # hash comment +├── file3.ts <-- left arrow comment +├── file4.ts --> right arrow comment +├── file5.ts any text here is comment +└── file6.ts (note: this is also a comment) +`; + + const result = parseTreeContent(input).nodes; + + // All text after filename is treated as comment (including markers) + expect(result[0].comment).toBe('// slash comment'); + expect(result[1].comment).toBe('# hash comment'); + expect(result[2].comment).toBe('<-- left arrow comment'); + expect(result[3].comment).toBe('--> right arrow comment'); + expect(result[4].comment).toBe('any text here is comment'); + expect(result[5].comment).toBe('(note: this is also a comment)'); }); From 55efaac27fdbfdd482ccee15732c7e527f396d4d Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:13:56 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E4=BA=86=EF=BC=81`.html`=20=E6=96=87=E4=BB=B6=E5=92=8C=20`...`?= =?UTF-8?q?=20=E7=9C=81=E7=95=A5=E5=8F=B7=E7=9A=84=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E9=83=BD=E6=98=AF=E6=AD=A3=E7=A1=AE=E7=9A=84=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `index.html` → type: `file`, extension: `html` - `about.html` → type: `file`, extension: `html` - `hello-world.html` → type: `file`, extension: `html` - `...` → type: `file` (不是目录) 如果你发现 `.html` 的图标没有正确显示,问题可能不在 parser,而在 icon 映射部分。需要我检查 `getFileIcon` 函数吗? --- .../tests/parser.spec.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/packages/rspress-plugin-file-tree/tests/parser.spec.ts b/packages/rspress-plugin-file-tree/tests/parser.spec.ts index 43ed2ab..bb1b4ae 100644 --- a/packages/rspress-plugin-file-tree/tests/parser.spec.ts +++ b/packages/rspress-plugin-file-tree/tests/parser.spec.ts @@ -803,3 +803,68 @@ test('Should treat any text after filename as comment', () => { expect(result[4].comment).toBe('any text here is comment'); expect(result[5].comment).toBe('(note: this is also a comment)'); }); + +test('Should parse .html files and ... ellipsis correctly', () => { + const input = ` +doc_build +├── static +│ ├── main.js +│ └── ... +├── index.html +├── about.html +├── posts +│ ├── hello-world.html +│ └── ... +`; + + const result = parseTreeContent(input).nodes; + + // doc_build is the root directory + const docBuild = result[0]; + expect(docBuild.name).toBe('doc_build'); + expect(docBuild.type).toBe('directory'); + + // static directory + const staticDir = docBuild.children[0]; + expect(staticDir.name).toBe('static'); + expect(staticDir.type).toBe('directory'); + + // main.js + const mainJs = staticDir.children[0]; + expect(mainJs.name).toBe('main.js'); + expect(mainJs.type).toBe('file'); + expect(mainJs.extension).toBe('js'); + + // ... ellipsis (should be treated as file, not directory) + const ellipsis1 = staticDir.children[1]; + expect(ellipsis1.name).toBe('...'); + expect(ellipsis1.type).toBe('file'); + + // index.html + const indexHtml = docBuild.children[1]; + expect(indexHtml.name).toBe('index.html'); + expect(indexHtml.type).toBe('file'); + expect(indexHtml.extension).toBe('html'); + + // about.html + const aboutHtml = docBuild.children[2]; + expect(aboutHtml.name).toBe('about.html'); + expect(aboutHtml.type).toBe('file'); + expect(aboutHtml.extension).toBe('html'); + + // posts directory + const postsDir = docBuild.children[3]; + expect(postsDir.name).toBe('posts'); + expect(postsDir.type).toBe('directory'); + + // hello-world.html + const helloWorldHtml = postsDir.children[0]; + expect(helloWorldHtml.name).toBe('hello-world.html'); + expect(helloWorldHtml.type).toBe('file'); + expect(helloWorldHtml.extension).toBe('html'); + + // ... ellipsis in posts + const ellipsis2 = postsDir.children[1]; + expect(ellipsis2.name).toBe('...'); + expect(ellipsis2.type).toBe('file'); +}); From c77dacf1862ba858d92e4257ae567296866f0085 Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:15:45 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E5=AE=8C=E6=88=90=EF=BC=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=9C=A8=E4=BA=8E=20`languages.ts`=20=E4=B8=AD?= =?UTF-8?q?=E7=BC=BA=E5=B0=91=20HTML=20=E5=9B=BE=E6=A0=87=E7=9A=84?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 已添加: ```typescript { id: 'html', icons: [ { name: 'html', content: () => import('material-icon-theme/icons/html.svg?raw'), matcher: /^.*\.html?$/, }, ], }, ``` 正则 `/^.*\.html?$/` 可以匹配 `.html` 和 `.htm` 两种扩展名。 --- .../src/components/languages.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/rspress-plugin-file-tree/src/components/languages.ts b/packages/rspress-plugin-file-tree/src/components/languages.ts index f568a58..b2a9e0d 100644 --- a/packages/rspress-plugin-file-tree/src/components/languages.ts +++ b/packages/rspress-plugin-file-tree/src/components/languages.ts @@ -101,4 +101,14 @@ export const SUPPORTED_LANGUAGES: LanguageDefinition[] = [ }, ], }, + { + id: 'html', + icons: [ + { + name: 'html', + content: () => import('material-icon-theme/icons/html.svg?raw'), + matcher: /^.*\.html?$/, + }, + ], + }, ]; From fa06c85b1fecf543437abb312e80d909a4ec5297 Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:19:57 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E5=AE=8C=E6=88=90=EF=BC=81=E6=89=80?= =?UTF-8?q?=E6=9C=89=2010=20=E4=B8=AA=E6=B5=8B=E8=AF=95=E9=83=BD=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 总结本次修改: **Parser 更新** (`tree-parser.ts`): - 在解析开始时检查第一行是否为 `.`(当前目录标记) - 如果是,则跳过该行,不将其作为节点 **新增测试**: - `Should skip leading . line (current directory marker)` - 验证以 `.` 开头的 tree 能正确跳过第一行 现在这种格式可以正确解析: ```tree . ├── docs │ └── index.mdx <-- "@rspress/core/theme" ├── theme │ └── index.tsx <-- "@rspress/core/theme-original" └── rspress.config.ts ``` 结果只有 3 个顶级节点:`docs`、`theme`、`rspress.config.ts`。 --- .../src/components/tree-parser/tree-parser.ts | 8 +++- .../tests/parser.spec.ts | 43 ++++++++++++++++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts index 16c7245..c341e6a 100644 --- a/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts +++ b/packages/rspress-plugin-file-tree/src/components/tree-parser/tree-parser.ts @@ -11,7 +11,13 @@ import { ParsedTree, TreeNode } from './types'; * └── another.ts */ export function parseTreeContent(content: string): ParsedTree { - const lines = content.split('\n').filter((line) => line.trim()); + let lines = content.split('\n').filter((line) => line.trim()); + + // Skip leading "." line (current directory marker) + if (lines.length > 0 && lines[0].trim() === '.') { + lines = lines.slice(1); + } + const nodes: TreeNode[] = []; const stack: { node: TreeNode; indent: number }[] = []; diff --git a/packages/rspress-plugin-file-tree/tests/parser.spec.ts b/packages/rspress-plugin-file-tree/tests/parser.spec.ts index bb1b4ae..a72336b 100644 --- a/packages/rspress-plugin-file-tree/tests/parser.spec.ts +++ b/packages/rspress-plugin-file-tree/tests/parser.spec.ts @@ -28,13 +28,6 @@ test('Should parse normal input', () => { `; expect(parseTreeContent(input).nodes).toMatchInlineSnapshot(` [ - { - "children": [], - "comment": undefined, - "extension": "", - "name": ".", - "type": "file", - }, { "children": [], "comment": undefined, @@ -804,6 +797,42 @@ test('Should treat any text after filename as comment', () => { expect(result[5].comment).toBe('(note: this is also a comment)'); }); +test('Should skip leading . line (current directory marker)', () => { + const input = ` +. +├── docs +│ └── index.mdx <-- "@rspress/core/theme" +├── theme +│ └── index.tsx <-- "@rspress/core/theme-original" +└── rspress.config.ts +`; + + const result = parseTreeContent(input).nodes; + + // Should have 3 top-level items (docs, theme, rspress.config.ts) + // The leading "." should be skipped + expect(result.length).toBe(3); + + // docs directory + const docsDir = result[0]; + expect(docsDir.name).toBe('docs'); + expect(docsDir.type).toBe('directory'); + expect(docsDir.children[0].name).toBe('index.mdx'); + expect(docsDir.children[0].comment).toBe('<-- "@rspress/core/theme"'); + + // theme directory + const themeDir = result[1]; + expect(themeDir.name).toBe('theme'); + expect(themeDir.type).toBe('directory'); + expect(themeDir.children[0].name).toBe('index.tsx'); + expect(themeDir.children[0].comment).toBe('<-- "@rspress/core/theme-original"'); + + // rspress.config.ts + const configTs = result[2]; + expect(configTs.name).toBe('rspress.config.ts'); + expect(configTs.type).toBe('file'); +}); + test('Should parse .html files and ... ellipsis correctly', () => { const input = ` doc_build From 7d78d2b4efd7407c2c719de39dbf784cba147c42 Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:26:17 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E5=AE=8C=E6=88=90=EF=BC=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=BE=88=E7=AE=80=E5=8D=95=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **FileTreeItem.tsx** 更新: ```tsx // Default to collapsed if directory has no children const hasChildren = node.type === 'directory' && node.children.length > 0; const [expanded, setExpanded] = useState(hasChildren); ``` 现在的行为: - 有子文件的目录:默认展开 (`expanded = true`) - 没有子文件的空目录:默认折叠 (`expanded = false`) --- .../src/components/FileTree/FileTreeItem.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx index f3037f6..aeb4810 100644 --- a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx +++ b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTreeItem.tsx @@ -12,7 +12,9 @@ interface FileTreeItemProps { const INDENT_SIZE = 12; export const FileTreeItem: React.FC = ({ node, depth }) => { - const [expanded, setExpanded] = useState(true); + // Default to collapsed if directory has no children + const hasChildren = node.type === 'directory' && node.children.length > 0; + const [expanded, setExpanded] = useState(hasChildren); const icon = useMemo(() => { if (node.type === 'directory') { From 1be1e0a3e58a33799401c253b37cafb7e3d48bbd Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:28:14 +0800 Subject: [PATCH 8/9] =?UTF-8?q?Changeset=20=E5=B7=B2=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=EF=BC=9A`.changeset/file-tree-improvements.md`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这是一个 patch 版本更新,包含以下改进: - 支持 2-space 和 4-space 两种缩进格式 - 支持文件名后的注释(任何文件名后的文本都作为注释) - 支持 `#`、`//`、`<--`、`-->` 等注释样式 - 跳过开头的 `.` 行(当前目录标记) - 添加 HTML 文件图标支持 - 空目录默认折叠 - 支持 `...` 省略号表示省略内容 --- .changeset/file-tree-improvements.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/file-tree-improvements.md diff --git a/.changeset/file-tree-improvements.md b/.changeset/file-tree-improvements.md new file mode 100644 index 0000000..4a00cc8 --- /dev/null +++ b/.changeset/file-tree-improvements.md @@ -0,0 +1,13 @@ +--- +"rspress-plugin-file-tree": patch +--- + +Improve file tree parser and UI: + +- Support both 2-space and 4-space indentation formats +- Support comments after filenames (any text after the filename is treated as comment) +- Support `#`, `//`, `<--`, `-->` and other comment styles +- Skip leading `.` line (current directory marker) +- Add HTML file icon support +- Empty directories now default to collapsed state +- Add `...` ellipsis support for omitted content From a5aa0f4e4e3cc361aef4b2f390079e98914d69ee Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 8 Jan 2026 02:33:17 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E5=B7=B2=E6=B7=BB=E5=8A=A0=20`background-c?= =?UTF-8?q?olor:=20var(--rp-code-block-bg);`=20=E5=88=B0=20`.container`=20?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=B8=AD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/FileTree/FileTree.module.less | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTree.module.less b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTree.module.less index 2b33ae2..c490023 100644 --- a/packages/rspress-plugin-file-tree/src/components/FileTree/FileTree.module.less +++ b/packages/rspress-plugin-file-tree/src/components/FileTree/FileTree.module.less @@ -8,5 +8,6 @@ border-radius: var(--rp-radius); border: var(--rp-code-block-border, 1px solid var(--rp-c-divider-light)); box-shadow: var(--rp-code-block-shadow, none); + background-color: var(--rp-code-block-bg); padding: 8px; }