feat: Beyond-Compare-style side-by-side viewer (PySide6) - #13
Merged
Conversation
Add compare_tool/view_model.py with two renderer-agnostic primitives that back the upcoming Qt two-pane viewer: - char_span(): intra-line changed span as plain character offsets (one contiguous span per side, common prefix/suffix excluded). - aligned_rows(): whole-file old/new alignment from classified hunks, with the shorter side of each changed block padded so the panes stay row-for-row aligned -- the natural Beyond-Compare model. report.py's _char_diff now consumes char_span, so the HTML report and the Qt viewer highlight the exact same characters and can never drift apart. HTML output is unchanged (existing report tests still pass). Add tests/test_view_model.py covering char_span offsets, agreement with the report highlighter, and aligned_rows padding/lockstep/monotonic-numbering. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add compare_tool/qtviewer, a PySide6 side-by-side compare app launched with `python -m compare_tool --qt [old] [new]`. This phase lands the shell: - tree.py: Qt-free folder-tree model (build_nodes + folder-status aggregation, error outranks all), unit-tested headless without PySide6. - worker.py: ScanWorker(QThread) runs scan off the GUI thread, results cross back via signals only. A worker crash emits a loud failure. - app.py: MainWindow with a QSplitter — folder tree left (verdict-coloured, matching the report's vocabulary) and a diff pane right. Uncompared paths raise a red COMPARE-INCOMPLETE banner; a Fusion dark palette matches the report identity. Selecting a file wires through to the diff pane. - diffpane.py: Phase-1 stub with the stable show_file/clear seam that the real two-pane view replaces in Phase 2. PySide6 is imported lazily (only under --qt), so the CLI and HTML report keep working on a headless box. Declared as an optional [viewer] extra; qtviewer added to the packaged modules. Add tests/test_qtviewer.py for the tree model. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the DiffPane stub with the real Beyond-Compare-style side-by-side view, built on the shared aligned_rows model: - DiffEditor: read-only monospace pane with a per-side line-number gutter that shows each row's ORIGINAL file line number (blank on padded rows), no wrap. - DiffPane: two DiffEditors in a splitter. Because aligned_rows emits one row per aligned line, both editors hold the same block count, so vertical and horizontal scrolling mirror across the panes with a simple reentrancy-guarded scrollbar link. - Row backgrounds follow the report palette (real red/green, minor yellow, moved blue, absent side dim filler); inline changed spans are highlighted at char_span offsets, marking the exact characters the HTML report marks. - A QStackedWidget switches to a message page for identical / added / deleted / binary / error files (added shows new content, deleted shows old). Render is wrapped fail-safe: a re-read failure shows a loud "treat as changed" message instead of an empty (unchanged-looking) diff. - On open, the view jumps to the first change. Verified offscreen: equal block counts, correct row modes, scroll mirror. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add compare_tool/qtviewer/minimap.py: a thin column down the right edge of the diff pane that compresses the whole file to one bar per changed row, coloured by mode (real red, minor yellow, moved blue). A translucent box tracks the visible viewport and click/drag jumps there. One minimap covers both panes: aligned_rows yields a single shared row sequence, so row i is the same vertical position on old and new. The map reads the old editor for its viewport and centres it to jump; the scrollbar mirror from Phase 2 carries the new pane along. It repaints on scroll and on content change, and clears for one-sided (added/deleted) and message views. Verified offscreen: marks placed at the changed rows, jump drives both panes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bring the Qt viewer to parity with the HTML report's richness: - Change navigation: F7/F8 (toolbar buttons too) step to the previous/next real or moved change and centre it; minor noise is skipped, and the ends wrap. Stops are the first row of each contiguous real/moved block. - Tree filter panel: a path search box plus "Show: Identical / Unimportant" toggles, both off by default so the tree opens on real changes only (matching the report's hide-noise default). filter_nodes is pure and unit-tested; empty folders collapse away and 'error' paths never hide. - Per-file AUTOSAR / A2L rollup under the diff header (+1 port, ~1 event, …), reusing the semantic diffs the scanner already attaches; moved-line count shown in the header. README: document --qt, the [viewer] extra, and note the viewer is the only part that needs PySide6. Verified offscreen: default tree hides noise, toggles/filter work, header shows the AUTOSAR rollup, F7/F8 cycle the changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add packaging/ so the viewer can ship as a single binary to machines with no Python: - viewer_entry.py: GUI-only frozen entry point (opens the viewer, optional OLD/NEW folder args), kept separate from compare_tool.main so the build carries no console/CLI baggage. - compare-viewer.spec: onefile PyInstaller spec resolving the repo root via SPECPATH; excludes the unused PySide6 addons (QtQuick, WebEngine, 3D, Charts, multimedia, …) so the binary is ~45 MB instead of 150 MB+. - build-viewer.ps1: one-command Windows build wrapper. README documents the standalone-exe build. Build artifacts (build/ dist/) are already gitignored. Verified: build completes and dist/CodeGenCompareViewer.exe launches and scans (offscreen smoke run). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a Beyond-Compare-style desktop viewer on top of the existing compare core: a folder tree plus a two-pane old/new diff with a change minimap. Built in 6 phases (one commit each) so it can be reviewed / rolled back phase by phase.
Why
The tool so far only produced a static HTML report. Reviewers wanted to browse a whole codegen tree interactively and see, per file, exactly what changed old-vs-new — for
.arxml,.a2land.c/.halike — with a minimap to spot change locations at a glance. Requested via AskUserQuestion: PySide6 native · read-only · tree left · two-pane right · minimap.What changed
compare_tool/view_model.py):char_span()(intra-line changed span as plain offsets) andaligned_rows()(whole-file old/new alignment from the classified hunks).report.pynow consumeschar_span, so the HTML report and the viewer highlight identical characters. HTML output is byte-identical (existing report tests still pass).compare_tool/qtviewer/):tree.py(Qt-free folder model + status aggregation),worker.py(ScanWorker(QThread), results via signals, loud crash),app.py(MainWindow, verdict-coloured tree, red COMPARE-INCOMPLETE banner, Fusion dark palette).char_span. Identical/added/deleted/binary/error render as a message page; render failures stay loud.F7/F8prev/next real change (noise skipped), tree path filter + Identical/Unimportant toggles (default off = hide noise), per-file AUTOSAR/A2L rollup in the header, moved-line count.packaging/): PyInstaller onefile spec (excludes unused PySide6 addons → ~45 MB) + Windows build script, producingCodeGenCompareViewer.exe.Notes for reviewers
python -m compare_tool --qt [old] [new]. PySide6 is imported only under--qt(deferred like tkinter), so the CLI, tkinter GUI and HTML report keep working on a headless box with no Qt. Declared as an optional[viewer]extra.test_view_model.py,test_qtviewer.pyexercise the pure logic), so CI needs no display. 175 tests pass. The Qt UI was verified with offscreen smoke runs (equal block counts + scroll mirror, minimap marks, filter/nav/semantics, frozen-exe launch + scan).dist//build/stay gitignored — the exe is not committed; runpackaging\build-viewer.ps1to produce it.🤖 Generated with Claude Code