Skip to content

Harden Quick Note formatting and persistence - #26

Draft
codebdbd wants to merge 3 commits into
masterfrom
codex/quick-note-reliability
Draft

Harden Quick Note formatting and persistence#26
codebdbd wants to merge 3 commits into
masterfrom
codex/quick-note-reliability

Conversation

@codebdbd

@codebdbd codebdbd commented Jul 28, 2026

Copy link
Copy Markdown
Owner

What changed

  • fixed empty/non-repeatable heading and list formatting controls and added a compact overflow menu
  • made clear-formatting a single document change that preserves selection, lists, and unselected rich hyperlink fragments
  • preserved nested Markdown combinations, formatted links, underline, strike, and code across save/reload
  • made note writes atomic, conflict copies collision-proof and discoverable after restart
  • strengthened external-edit detection with existence, metadata, and SHA-256 content baselines
  • improved close/save coordination, modal focus handling, settings-save safety, and multi-monitor geometry restore
  • preserved selected whitespace when inserting links
  • added focused unit and WPF regression coverage

Why

Quick Note formatting controls could appear empty or fail on repeated choices, clear-formatting flickered and could damage selection/link structure, and several persistence edge cases could lose formatting or mishandle external edits. This hardens the existing lightweight single-note architecture without changing its Markdown storage format.

Validation

  • dotnet build .\AiteBar.sln -c Release — 0 warnings, 0 errors
  • dotnet test .\AiteBar.Tests\AiteBar.Tests.csproj -c Release --no-build — 751/751 passed on a clean branch from origin/master
  • Quick Note focused suite — 129/129 passed
  • .\installer\Build-Installer.ps1 — succeeded
  • installer SHA-256: B0BEA5C6D060714DC0749899729AE470E94F284B7315E90AACC7A8F304E07242

Code signing was skipped because no signing certificate was supplied.

Review follow-up

  • bounded forced-save semaphore waiting to 10 seconds while preserving the WPF dispatcher context
  • centralized link URL extraction and added strict HTTP(S), mailto:, and tel: payload validation
  • switched URL/email/phone detection to the .NET non-backtracking regex engine
  • limited conflict-copy tooltip disclosure to the file name
  • added rejection tests for file:, javascript:, shell-metacharacter, and traversal-like payloads

Contract cleanup

  • centralized WPF tag serialization/parsing for headings, indentation, code, and links
  • reused one default/code font contract instead of recreating FontFamily values
  • removed the duplicate Markdown newline normalizer
  • replaced resize string fallback with validated enum parsing; invalid tags are ignored
  • added coverage for all eight resize edges and invalid tag values

Comment on lines +41 to +45
string code = File.ReadAllText(Path.Combine(
AppContext.BaseDirectory,
"..", "..", "..", "..",
"AiteBar",
"QuickNoteWindow.xaml.cs"));

private static XDocument LoadDocument()
{
string path = Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "AiteBar", "QuickNoteWindow.xaml");
[Fact]
public async Task ReadMarkdownAsync_RestoresLatestConflictCopyAfterServiceRestart()
{
string older = Path.Combine(_tempDir, "QuickNote.conflict-older.md");
public async Task ReadMarkdownAsync_RestoresLatestConflictCopyAfterServiceRestart()
{
string older = Path.Combine(_tempDir, "QuickNote.conflict-older.md");
string latest = Path.Combine(_tempDir, "QuickNote.conflict-latest.md");
{
RunSta(() =>
{
string tempRoot = Path.Combine(Path.GetTempPath(), "AiteBarTests", Guid.NewGuid().ToString("N"));
{
var settingsService = new AppSettingsService(
Path.Combine(tempRoot, "buttons.json"),
Path.Combine(tempRoot, "settings.json"));
Comment on lines +216 to +219
catch (Exception ex)
{
exception = ex;
}
Comment on lines +228 to +231
catch (Exception ex)
{
Logger.Log(ex);
}
private static async Task WriteAtomicallyAsync(string path, string content)
{
string directory = Path.GetDirectoryName(path) ?? Directory.GetCurrentDirectory();
string tempPath = Path.Combine(directory, $".{Path.GetFileName(path)}.{Guid.NewGuid():N}.tmp");
Comment on lines +1862 to +1865
catch (Exception ex)
{
Logger.Log(ex);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants