fix(export): drop invalid file-name characters from the suggested export name
A workspace at a drive root is named "D:\", which made the suggested file name invalid. Characters that are invalid in a file name on any supported platform are now removed, and a name left empty (a workspace at /) falls back to YKanBan.
This commit is contained in:
1 parent
05a5169129
commit
1ecb48316d
3 files changed
+36
-4
No files matched your search
@@ -181,6 +181,21 @@ public class MarkdownExporterTests
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow("D:\\", "D")]
|
||||
[DataRow("a<b>c|d?e*f\"g", "abcdefg")]
|
||||
[DataRow("/", null)]
|
||||
public void FileNameDropsCharactersThatAreInvalidInFileNames(string workspaceName, string? expectedName)
|
||||
{
|
||||
string fileName = MarkdownExporter.BuildFileName(workspaceName, ExportedAt);
|
||||
|
||||
CultureInfo culture = Resources.Culture ?? CultureInfo.CurrentUICulture;
|
||||
Assert.AreEqual(
|
||||
string.Format(culture, Resources.Export_FileNamePattern, expectedName ?? Resources.App_Name, ExportedAt),
|
||||
fileName);
|
||||
Assert.AreEqual(-1, fileName.IndexOfAny(Path.GetInvalidFileNameChars()));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TagTableCellsEscapePipesAndLineBreaks()
|
||||
{
|
||||
|
||||
@@ -67,7 +67,10 @@ public static class MarkdownExporter
|
||||
|
||||
/// <summary>
|
||||
/// Builds the default export file name in the UI language, for example
|
||||
/// "MyRepo-export-20260930-142537.md".
|
||||
/// "MyRepo-export-20260930-142537.md". Characters that are not allowed in a
|
||||
/// file name on any supported platform are dropped from the workspace name
|
||||
/// (a workspace at a drive root is named "D:\"); a name left empty falls
|
||||
/// back to the application name.
|
||||
/// </summary>
|
||||
/// <param name="workspaceName">Workspace display name.</param>
|
||||
/// <param name="exportedAt">Export moment.</param>
|
||||
@@ -75,8 +78,22 @@ public static class MarkdownExporter
|
||||
public static string BuildFileName(string workspaceName, DateTimeOffset exportedAt)
|
||||
{
|
||||
CultureInfo culture = Resources.Culture ?? CultureInfo.CurrentUICulture;
|
||||
return string.Format(culture, Resources.Export_FileNamePattern, workspaceName, exportedAt);
|
||||
string safeName = new(workspaceName.Where(character => !IsInvalidFileNameCharacter(character)).ToArray());
|
||||
if (safeName.Length == 0)
|
||||
{
|
||||
safeName = Resources.App_Name;
|
||||
}
|
||||
return string.Format(culture, Resources.Export_FileNamePattern, safeName, exportedAt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells whether a character is invalid in a file name on Windows, Linux or
|
||||
/// macOS; the Windows set is the widest, so the result is the same on every platform.
|
||||
/// </summary>
|
||||
/// <param name="character">The character to test.</param>
|
||||
/// <returns><see langword="true"/> when the character must not appear in a file name.</returns>
|
||||
private static bool IsInvalidFileNameCharacter(char character) =>
|
||||
character < ' ' || character is '<' or '>' or ':' or '"' or '/' or '\\' or '|' or '?' or '*';
|
||||
|
||||
/// <summary>
|
||||
/// Appends one card block: heading, body, tags line and timestamps line.
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
- 网络共享明确不支持;命令行参数边界;macOS 无参启动行为写入文档(§2.3、§4.1、附录)
|
||||
- 补充:导出转义规则、卡片列表虚拟化、模态窗口 FlowDirection、`Resources` 类名使用规则、CI osx-x64 运行器(§5、§7、§8)
|
||||
- 依赖:Avalonia 11.3.6 → 11.3.22,Semi.Avalonia 11.2.1.10 → 11.3.22(§7)
|
||||
- 实现回补:搜索括号嵌套上限 64 层、单个表达式至多 256 个原子,空短语、短语紧贴文本、`key:` 后空白均为非法(§6.1、§6.2);导出表格单元格转义 `\`(§5.8);初始化中途锁冲突进锁冲突页、数据库文件缺失不静默新建(§4.4);app.json 读不出 / 备份写不出 / 退出写盘失败均不阻断启动与退出(§4.3)
|
||||
- 实现回补:搜索括号嵌套上限 64 层、单个表达式至多 256 个原子,空短语、短语紧贴文本、`key:` 后空白均为非法(§6.1、§6.2);导出表格单元格转义 `\`、默认文件名剔除非法字符(§5.8);初始化中途锁冲突进锁冲突页、数据库文件缺失不静默新建(§4.4);app.json 读不出 / 备份写不出 / 退出写盘失败均不阻断启动与退出(§4.3)
|
||||
- 里程碑:标注 M0–M4 已完成,新增 **M4R(v1.9 回补)**(§9)
|
||||
|
||||
## 1. 项目概述
|
||||
@@ -223,7 +223,7 @@ card_tags: (card_id, tag_id) 复合主键,双向 ON DELETE CASCADE
|
||||
|
||||
### 5.8 导出
|
||||
|
||||
- 点击后弹系统保存文件对话框,默认文件名按当前语言生成(模式为资源键,**精确到秒**):英文 `MyRepo-export-20260930-142537.md`;中文 `MyRepo-导出-20260930-142537.md`
|
||||
- 点击后弹系统保存文件对话框,默认文件名按当前语言生成(模式为资源键,**精确到秒**):英文 `MyRepo-export-20260930-142537.md`;中文 `MyRepo-导出-20260930-142537.md`;工作区名中任一平台的文件名非法字符(`<>:"/\|?*` 与控制字符)剔除,剔除后为空(如工作区位于 `/`)则用 `YKanBan`
|
||||
- 人类可读格式,无回导需求;模板文本直接读取 ResX 资源(见 §8),导出语言跟随当前界面语言
|
||||
- 导出范围为工作区全量数据,不受当前搜索筛选与卡片排序选项影响:列按 id 升序,列内卡片按 id 升序
|
||||
- 全文时间戳(导出时间与卡片创建/修改时间)格式随语言:英文 `yyyy-MM-dd HH:mm:ss`;中文 `yyyy年M月d日 HH:mm`
|
||||
|
||||
Reference in new issue
Block a user