From 937e43028d6dc389c74ad6ba266c1ad5daba83a8 Mon Sep 17 00:00:00 2001 From: Zcube7 Date: Thu, 20 Aug 2026 17:47:33 +0800 Subject: [PATCH 1/2] Release ZCompare v0.1.2 detail highlighting fixes --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- CHANGELOG.md | 15 +- Directory.Build.props | 8 +- README.md | 10 +- README.zh-CN.md | 10 +- docs/INSTALL.md | 10 +- docs/INSTALL.zh-CN.md | 10 +- installer/ZCompare.iss | 2 +- .../Controls/DifferenceTextColumn.cs | 76 +++++ src/ZCompare.App/DetailsWindow.xaml | 22 +- src/ZCompare.App/DetailsWindow.xaml.cs | 39 ++- src/ZCompare.App/MainWindow.xaml | 44 ++- src/ZCompare.App/MainWindow.xaml.cs | 64 ++-- .../ViewModels/MainWindowViewModel.cs | 135 ++++++++- .../ViewModels/PresentationModels.cs | 18 +- .../ViewModels/TextDifferenceHighlighter.cs | 279 ++++++++++++++++++ src/ZCompare.App/ZCompare.App.csproj | 6 - .../ZCompare.App.Tests/DetailsWindowTests.cs | 54 ++++ .../MainWindowSmokeTests.cs | 92 ++++++ .../PresentationModelsTests.cs | 8 +- .../TextDifferenceHighlighterTests.cs | 205 +++++++++++++ tests/ZCompare.Tests/CliIntegrationTests.cs | 2 +- .../ComparisonReportExporterTests.cs | 2 +- 23 files changed, 1029 insertions(+), 84 deletions(-) create mode 100644 src/ZCompare.App/Controls/DifferenceTextColumn.cs create mode 100644 src/ZCompare.App/ViewModels/TextDifferenceHighlighter.cs create mode 100644 tests/ZCompare.App.Tests/DetailsWindowTests.cs create mode 100644 tests/ZCompare.App.Tests/MainWindowSmokeTests.cs create mode 100644 tests/ZCompare.App.Tests/TextDifferenceHighlighterTests.cs diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9ed7b33..704ee06 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -10,7 +10,7 @@ body: id: version attributes: label: ZCompare version - placeholder: 0.1.1 + placeholder: 0.1.2 validations: required: true - type: dropdown diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b249f..138d262 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to ZCompare are documented here. The project follows [Semant ## [Unreleased] +## [0.1.2] - 2026-08-20 + +### Added + +- Added complete raw/display-value viewing with horizontal scrolling for long cell contents. +- Highlighted changed character spans in both the worksheet grid and cell-detail window while keeping copied text unmodified. + +### Fixed + +- Fixed a crash when double-clicking highlighted text inside a differing cell. +- Removed synthetic `⟦ ⟧` difference markers from cell-detail text and preserved real brackets, whitespace, and trailing spaces when copying. + ## [0.1.1] - 2026-08-12 ### Fixed @@ -21,6 +33,7 @@ All notable changes to ZCompare are documented here. The project follows [Semant - Safe handling for stale formula caches, changed source files, unsupported ISO Strict files, and unreadable containers. - Per-user Windows installer, portable developer package, release checksums, and non-intrusive update notification. -[Unreleased]: https://github.com/Zcube7/ZCompare/compare/v0.1.1...HEAD +[Unreleased]: https://github.com/Zcube7/ZCompare/compare/v0.1.2...HEAD +[0.1.2]: https://github.com/Zcube7/ZCompare/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/Zcube7/ZCompare/compare/v0.1.0...v0.1.1 [0.1.0]: https://github.com/Zcube7/ZCompare/releases/tag/v0.1.0 diff --git a/Directory.Build.props b/Directory.Build.props index 6c84d41..0153b07 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,10 +5,10 @@ enable true true - 0.1.1 - 0.1.1.0 - 0.1.1.0 - 0.1.1 + 0.1.2 + 0.1.2.0 + 0.1.2.0 + 0.1.2 ZCompare ZCompare Zcube7 diff --git a/README.md b/README.md index 0c936dc..83e53b1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ZCompare is a read-only Windows tool for people who maintain XLSX files across long-lived versions. It compares two workbooks or two folders, aligns inserted/deleted rows conservatively, and presents the result in synchronized spreadsheet views. -> Public preview: **v0.1.1** supports Windows 10/11 x64 and genuine OOXML `.xlsx` files only. +> Public preview: **v0.1.2** supports Windows 10/11 x64 and genuine OOXML `.xlsx` files only. ![ZCompare workbook comparison using synthetic data](docs/images/zcompare-workbook-diff.png) @@ -21,11 +21,11 @@ ZCompare is a read-only Windows tool for people who maintain XLSX files across l Download assets only from the official [ZCompare Releases](https://github.com/Zcube7/ZCompare/releases) page. -- **Most users:** `ZCompare-0.1.1-win-x64-setup.exe`. Per-user install; no administrator rights or preinstalled .NET required. -- **Developers / advanced users:** `ZCompare-0.1.1-win-x64-portable-fdd.zip`. Requires the .NET 10 Desktop Runtime x64 and includes both GUI and CLI. +- **Most users:** `ZCompare-0.1.2-win-x64-setup.exe`. Per-user install; no administrator rights or preinstalled .NET required. +- **Developers / advanced users:** `ZCompare-0.1.2-win-x64-portable-fdd.zip`. Requires the .NET 10 Desktop Runtime x64 and includes both GUI and CLI. - Verify downloads with `SHA256SUMS.txt`. -The first release is not code-signed. Windows SmartScreen may show a warning. Verify the GitHub repository, filename, and SHA-256 before choosing **More info → Run anyway**. Do not disable SmartScreen. +The current release is not code-signed. Windows SmartScreen may show a warning. Verify the GitHub repository, filename, and SHA-256 before choosing **More info → Run anyway**. Do not disable SmartScreen. Detailed instructions: [English](docs/INSTALL.md) · [简体中文](docs/INSTALL.zh-CN.md) @@ -79,7 +79,7 @@ After the window loads, ZCompare performs a non-blocking update check against Gi - No telemetry and no workbook/report upload. - The update request sends only standard HTTP headers and the app version to GitHub. - Recent paths and named profiles are stored locally under `%LocalAppData%\ZCompare`. -- Error dialogs stay local; v0.1.1 does not create or upload diagnostic logs. +- Error dialogs stay local; v0.1.2 does not create or upload diagnostic logs. - Source files are hashed before and after comparison and are never written by ZCompare. See the [installation guide](docs/INSTALL.md) for the full privacy and AI-assisted installation checklist. diff --git a/README.zh-CN.md b/README.zh-CN.md index 38b9810..f7be4d9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@ ZCompare 是面向长期跨版本管理、维护 XLSX 文件用户的只读 Windows 对比工具。它支持双工作簿与双文件夹对比,能够保守对齐插入/删除行,并在同步滚动的左右表格中清晰展示结果。 -> 公开预览版:**v0.1.1**,支持 Windows 10/11 x64,仅支持真实 OOXML `.xlsx` 文件。 +> 公开预览版:**v0.1.2**,支持 Windows 10/11 x64,仅支持真实 OOXML `.xlsx` 文件。 ![使用合成数据的 ZCompare 工作簿对比](docs/images/zcompare-workbook-diff.png) @@ -21,11 +21,11 @@ ZCompare 是面向长期跨版本管理、维护 XLSX 文件用户的只读 Wind 只从官方 [ZCompare Releases](https://github.com/Zcube7/ZCompare/releases) 页面下载。 -- **普通用户推荐:** `ZCompare-0.1.1-win-x64-setup.exe`。当前用户安装,无需管理员权限,也无需预装 .NET。 -- **开发者/高级用户:** `ZCompare-0.1.1-win-x64-portable-fdd.zip`。需要 .NET 10 Desktop Runtime x64,包含 GUI 与 CLI。 +- **普通用户推荐:** `ZCompare-0.1.2-win-x64-setup.exe`。当前用户安装,无需管理员权限,也无需预装 .NET。 +- **开发者/高级用户:** `ZCompare-0.1.2-win-x64-portable-fdd.zip`。需要 .NET 10 Desktop Runtime x64,包含 GUI 与 CLI。 - 使用 `SHA256SUMS.txt` 校验下载文件。 -首版暂未购买代码签名,Windows SmartScreen 可能显示风险提示。请先核对 GitHub 官方仓库、文件名和 SHA-256,再按正常流程选择 **“更多信息”→“仍要运行”**;不要关闭 SmartScreen。 +当前版本暂未购买代码签名,Windows SmartScreen 可能显示风险提示。请先核对 GitHub 官方仓库、文件名和 SHA-256,再按正常流程选择 **“更多信息”→“仍要运行”**;不要关闭 SmartScreen。 完整指南:[普通安装、便携版、源码与 AI 辅助安装](docs/INSTALL.zh-CN.md) @@ -79,7 +79,7 @@ dotnet run --project src/ZCompare.App/ZCompare.App.csproj - 无遥测,不上传工作簿或报告。 - 更新请求只向 GitHub 发送标准 HTTP 头和程序版本。 - 最近路径与命名配置只保存在 `%LocalAppData%\ZCompare`。 -- 错误提示仅在本机显示;v0.1.1 不生成或上传诊断日志。 +- 错误提示仅在本机显示;v0.1.2 不生成或上传诊断日志。 - 对比前后复核源文件 SHA-256,ZCompare 不写入源文件。 完整隐私和 AI 辅助安装注意事项见[安装指南](docs/INSTALL.zh-CN.md)。 diff --git a/docs/INSTALL.md b/docs/INSTALL.md index a6cd83d..f325c8a 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -5,24 +5,24 @@ ## Option A: installer (recommended) 1. Open the official [ZCompare Releases](https://github.com/Zcube7/ZCompare/releases) page. -2. Download `ZCompare-0.1.1-win-x64-setup.exe` and `SHA256SUMS.txt`. +2. Download `ZCompare-0.1.2-win-x64-setup.exe` and `SHA256SUMS.txt`. 3. Verify the SHA-256 value: ```powershell - Get-FileHash .\ZCompare-0.1.1-win-x64-setup.exe -Algorithm SHA256 + Get-FileHash .\ZCompare-0.1.2-win-x64-setup.exe -Algorithm SHA256 Get-Content .\SHA256SUMS.txt ``` 4. Run the installer. It installs for the current user under `%LocalAppData%\Programs\ZCompare` and does not require administrator rights or a separate .NET installation. -The installer is not code-signed in v0.1.1. SmartScreen may warn about an unrecognized app. Continue through **More info → Run anyway** only after verifying the official source and checksum. Never disable SmartScreen for installation. +The installer is not code-signed in v0.1.2. SmartScreen may warn about an unrecognized app. Continue through **More info → Run anyway** only after verifying the official source and checksum. Never disable SmartScreen for installation. Future installers use the same AppId and upgrade in place. Uninstalling the app does not remove recent comparisons and profiles from `%LocalAppData%\ZCompare`. ## Option B: portable developer package 1. Install the [.NET 10 Desktop Runtime x64](https://dotnet.microsoft.com/download/dotnet/10.0). -2. Download and verify `ZCompare-0.1.1-win-x64-portable-fdd.zip`. +2. Download and verify `ZCompare-0.1.2-win-x64-portable-fdd.zip`. 3. Extract the archive into a new folder. 4. Run `ZCompare.App.exe`, or open a terminal in that folder and run `zcompare.exe --help`. @@ -54,4 +54,4 @@ ZCompare checks the latest stable GitHub Release in the background at most once ## Network and privacy -The application does not send workbooks, paths, reports, or settings to a server. The optional update check contacts `api.github.com` and sends only standard HTTP headers plus the installed version. Recent paths and update-cache metadata stay under `%LocalAppData%\ZCompare`. No diagnostic log file is created in v0.1.1. +The application does not send workbooks, paths, reports, or settings to a server. The optional update check contacts `api.github.com` and sends only standard HTTP headers plus the installed version. Recent paths and update-cache metadata stay under `%LocalAppData%\ZCompare`. No diagnostic log file is created in v0.1.2. diff --git a/docs/INSTALL.zh-CN.md b/docs/INSTALL.zh-CN.md index 2c8607c..80cf80a 100644 --- a/docs/INSTALL.zh-CN.md +++ b/docs/INSTALL.zh-CN.md @@ -5,24 +5,24 @@ ## 方式 A:安装包(推荐) 1. 打开官方 [ZCompare Releases](https://github.com/Zcube7/ZCompare/releases) 页面。 -2. 下载 `ZCompare-0.1.1-win-x64-setup.exe` 和 `SHA256SUMS.txt`。 +2. 下载 `ZCompare-0.1.2-win-x64-setup.exe` 和 `SHA256SUMS.txt`。 3. 校验 SHA-256: ```powershell - Get-FileHash .\ZCompare-0.1.1-win-x64-setup.exe -Algorithm SHA256 + Get-FileHash .\ZCompare-0.1.2-win-x64-setup.exe -Algorithm SHA256 Get-Content .\SHA256SUMS.txt ``` 4. 运行安装包。程序会安装到当前用户的 `%LocalAppData%\Programs\ZCompare`,不需要管理员权限,也不需要另装 .NET。 -v0.1.1 暂未购买代码签名,因此 SmartScreen 可能提示“无法识别的应用”。只有在确认来源是官方仓库且 SHA-256 一致后,才按 **“更多信息”→“仍要运行”**;不要关闭 SmartScreen。 +v0.1.2 暂未购买代码签名,因此 SmartScreen 可能提示“无法识别的应用”。只有在确认来源是官方仓库且 SHA-256 一致后,才按 **“更多信息”→“仍要运行”**;不要关闭 SmartScreen。 以后版本使用同一个 AppId,会原位覆盖升级。卸载程序默认不会删除 `%LocalAppData%\ZCompare` 中的最近记录和命名配置。 ## 方式 B:便携开发者包 1. 安装 [.NET 10 Desktop Runtime x64](https://dotnet.microsoft.com/download/dotnet/10.0)。 -2. 下载并校验 `ZCompare-0.1.1-win-x64-portable-fdd.zip`。 +2. 下载并校验 `ZCompare-0.1.2-win-x64-portable-fdd.zip`。 3. 解压到一个新文件夹。 4. 运行 `ZCompare.App.exe`;需要 CLI 时,在该目录打开终端并运行 `zcompare.exe --help`。 @@ -54,4 +54,4 @@ ZCompare 最多每 24 小时在后台查询一次 GitHub 最新稳定 Release。 ## 网络与隐私 -程序不会把工作簿、路径、报告或设置发送到服务器。更新检查只访问 `api.github.com`,发送标准 HTTP 头和已安装版本。最近路径与更新缓存保存在 `%LocalAppData%\ZCompare`。v0.1.1 不生成诊断日志文件。 +程序不会把工作簿、路径、报告或设置发送到服务器。更新检查只访问 `api.github.com`,发送标准 HTTP 头和已安装版本。最近路径与更新缓存保存在 `%LocalAppData%\ZCompare`。v0.1.2 不生成诊断日志文件。 diff --git a/installer/ZCompare.iss b/installer/ZCompare.iss index f791e21..bfefd62 100644 --- a/installer/ZCompare.iss +++ b/installer/ZCompare.iss @@ -1,5 +1,5 @@ #ifndef MyAppVersion - #define MyAppVersion "0.1.1" + #define MyAppVersion "0.1.2" #endif #ifndef SourceDir #define SourceDir "..\artifacts\release-staging\installer-payload" diff --git a/src/ZCompare.App/Controls/DifferenceTextColumn.cs b/src/ZCompare.App/Controls/DifferenceTextColumn.cs new file mode 100644 index 0000000..a292ac7 --- /dev/null +++ b/src/ZCompare.App/Controls/DifferenceTextColumn.cs @@ -0,0 +1,76 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Media; +using ZCompare.App.ViewModels; + +namespace ZCompare.App.Controls; + +internal sealed class DifferenceTextBlock : TextBlock +{ + private static readonly Brush DifferenceBrush = CreateDifferenceBrush(); + + public static readonly DependencyProperty SegmentsProperty = DependencyProperty.Register( + nameof(Segments), + typeof(IReadOnlyList), + typeof(DifferenceTextBlock), + new PropertyMetadata(null, SegmentsChanged)); + + public IReadOnlyList? Segments + { + get => (IReadOnlyList?)GetValue(SegmentsProperty); + set => SetValue(SegmentsProperty, value); + } + + private static void SegmentsChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs) + { + var textBlock = (DifferenceTextBlock)dependencyObject; + textBlock.Inlines.Clear(); + foreach (var segment in eventArgs.NewValue as IReadOnlyList ?? []) + { + var run = new Run(segment.Text); + if (segment.IsDifferent) + { + run.Foreground = DifferenceBrush; + run.FontWeight = FontWeights.Bold; + } + + textBlock.Inlines.Add(run); + } + } + + private static Brush CreateDifferenceBrush() + { + var brush = new SolidColorBrush(Color.FromRgb(153, 27, 27)); + brush.Freeze(); + return brush; + } +} + +internal sealed class DifferenceTextColumn : DataGridBoundColumn +{ + public BindingBase? SegmentsBinding { get; init; } + + protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) => + CreateElement(); + + protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) => + CreateElement(); + + private FrameworkElement CreateElement() + { + var element = new DifferenceTextBlock(); + if (ElementStyle is not null) + { + element.Style = ElementStyle; + } + + if (SegmentsBinding is not null) + { + BindingOperations.SetBinding(element, DifferenceTextBlock.SegmentsProperty, SegmentsBinding); + } + + return element; + } +} diff --git a/src/ZCompare.App/DetailsWindow.xaml b/src/ZCompare.App/DetailsWindow.xaml index d544b66..ae54331 100644 --- a/src/ZCompare.App/DetailsWindow.xaml +++ b/src/ZCompare.App/DetailsWindow.xaml @@ -13,17 +13,17 @@ - + + + + +