Skip to content

Fix Markdown/bulk export review follow-ups from PR #19#20

Open
bigbruno wants to merge 1 commit into
mainfrom
fix/md-export-review-followups
Open

Fix Markdown/bulk export review follow-ups from PR #19#20
bigbruno wants to merge 1 commit into
mainfrom
fix/md-export-review-followups

Conversation

@bigbruno
Copy link
Copy Markdown
Member

Summary

Address the ten findings from the post-merge code review of PR #19. Pure correctness + UI/UX polish — no new features.

Converter (utils/tsv_odf_converter.py)

  • _MD_LINE_START_RE now requires whitespace/EOL after \d+\. so 1.5 million / 2025.06 release no longer escape to \1.5 million.
  • _emit_kv emits blank lines before and after so adjacent KV entries stay distinct CommonMark paragraphs.
  • _emit_paragraph honours DocElement.raw_lines via hard breaks (two trailing spaces) for multi-line addresses, poetry, etc.

Markdown export UI (ui/conclusion_export_mixin.py)

  • Atomic single-file write (*.tmp + os.replace) so a failed/cancelled conversion no longer destroys a pre-existing target file.
  • Remote URI guard (Gio.File.get_path() is None) for both the single-file save dialog and the bulk folder picker — clear toast instead of swallowed AttributeError.
  • Per-row export flags now flow through a closure chain (include_front_matter, open_after) instead of self attributes, so overlapping dialogs can't clobber each other.
  • Bulk folder picker surfaces non-Dismiss errors with _EXPORT_FAILED_MSG.
  • _run_bulk_export snapshots md_include_front_matter / odf_include_images at batch start; a mid-batch toggle can no longer produce a non-uniform batch.
  • Bulk MD path uses the same atomic write as single-file.
  • Unknown fmt in _BULK_EXTENSIONS closes the dialog and toasts a real failure instead of "Saved 0 files".
  • Cancel button on _build_progress_dialog now disables itself, swaps label + AT-SPI accessible name to Cancelling…, and rewrites subtitle to Finishing current step…. Progress callback short-circuits after cancel so late updates can't overwrite the message — gives immediate feedback while parse_tsv_pages finishes.

Settings persistence (services/settings.py)

  • New _load_md_settings / _save_md_settings cover md_export.include_front_matter and md_export.open_after_export; wired into load_settings / _save_all_settings.
  • _update_md_setting calls settings._save_md_settings() so toggling either Markdown option now persists across restarts, matching the ODF flow.

Test plan

  • pytest364 passing (+6 new):
    • decimal at line start not escaped
    • KV elements separated by blank line
    • paragraph preserves raw lines (hard breaks)
    • _save_md_settings writes both keys
    • _load_md_settings reads both keys
    • _save_md_settings defaults when unset
  • ruff check src/ tests/ clean
  • ruff format --check clean on touched files
  • Independent UI/UX revalidation pass on cancel feedback, remote-URI guard, folder-picker error toast, options dialog persistence, closure-bound flags, atomic write, bulk options snapshot, and KV separation: PASS

🤖 Generated with Claude Code

Apply the ten code-review findings on the freshly-merged Markdown +
bulk export workflow. No new features; correctness and UI/UX only.

Converter (tsv_odf_converter.py):

- _MD_LINE_START_RE: require whitespace (or end of string) after the
  digits-dot pattern so paragraphs starting with a decimal like
  "1.5 million" or "2025.06 release" are no longer mangled to
  "\1.5 million".
- _emit_kv: emit blank lines before and after so adjacent KV elements
  no longer collapse into one CommonMark paragraph and the bolded key
  stays visually distinct.
- _emit_paragraph: when DocElement.raw_lines preserved per-line breaks
  (multi-line addresses, poetry), emit each line with a CommonMark
  hard break (two trailing spaces) instead of collapsing into a single
  run-on line.

Markdown export UI (conclusion_export_mixin.py):

- _export_markdown_file: write to "<path>.tmp" then os.replace so a
  failed/cancelled conversion no longer destroys a pre-existing file
  the user picked to overwrite via FileDialog.
- _on_md_save_response: guard against Gio.File.get_path() == None
  (remote/MTP/GVfs locations) and surface a clear toast instead of an
  AttributeError swallowed as a generic "Export failed".
- _on_md_export_clicked → _on_md_save_response → _export_markdown_file
  → _on_md_export_finished: pass include_front_matter and open_after
  through the closure chain instead of self attributes, so overlapping
  per-row exports can no longer clobber each other's settings.
- _on_folder_chosen (bulk): show _EXPORT_FAILED_MSG on non-Dismiss
  errors so the user gets feedback instead of a silently-vanishing
  dialog; also guards remote folders with the same toast as the
  single-file path.
- _run_bulk_export / _bulk_convert_one: snapshot md_include_front_matter
  and odf_include_images once at batch start and pass them via an
  options dict, so a mid-batch toggle from another dialog can no longer
  produce a non-uniform batch.
- _bulk_convert_one (md branch): write to "<path>.tmp" and os.replace,
  matching the single-file atomic-write pattern.
- _bulk_export_worker: when fmt is not in _BULK_EXTENSIONS, close the
  dialog and toast a real export-failed message instead of falling
  back to a misleading "Saved 0 files".
- _build_progress_dialog: cancel handler now disables the button,
  swaps its label and AT-SPI accessible name to "Cancelling…", and
  rewrites the subtitle to "Finishing current step…". The progress
  callback short-circuits after cancel so the message doesn't get
  overwritten by late per-file updates. Gives the user immediate
  feedback while parse_tsv_pages finishes its current step on a long
  PDF.

Settings persistence (services/settings.py):

- Add _load_md_settings / _save_md_settings handling the
  md_export.include_front_matter and md_export.open_after_export
  config keys; hooked into load_settings / _save_all_settings.
- _update_md_setting (UI) now calls settings._save_md_settings()
  before config.save() so the Markdown toggles actually persist
  across restarts, matching the ODF flow.

Tests (test_markdown_export.py):

- TestEscapeMd.test_decimal_at_line_start_not_escaped: pins the new
  decimal-aware behavior; "1." alone still escapes via the end-of-
  string boundary.
- TestCreateMarkdown.test_kv_elements_separated_by_blank_line: pins
  the new KV separator rule.
- TestCreateMarkdown.test_paragraph_preserves_raw_lines: pins the new
  hard-break handling for multi-line OCR paragraphs.
- TestSaveMdSettings.{test_save_md_settings_writes_both_keys,
  test_load_md_settings_reads_both_keys,
  test_save_md_settings_defaults_when_unset}: cover the new persistence
  path end-to-end with a minimal config double.

364 passing tests, ruff clean.
@codacy-production
Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 20 complexity · 2 duplication

Metric Results
Complexity 20
Duplication 2

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@sonarqubecloud
Copy link
Copy Markdown

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.

1 participant