Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
run: |
for tool in "dist/compare-tool.exe" "python dist/compare_tool.pyz"; do
set +e
$tool tests/fixtures/old tests/fixtures/new --report out.html
$tool tests/fixtures/demo/old tests/fixtures/demo/new --report out.html
code=$?
set -e
test "$code" -eq 1 || { echo "::error::$tool exited $code, expected 1"; exit 1; }
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
shell: bash
run: |
set +e
python dist/compare_tool.pyz tests/fixtures/old tests/fixtures/new --report pyz.html
python dist/compare_tool.pyz tests/fixtures/demo/old tests/fixtures/demo/new --report pyz.html
code=$?
set -e
test "$code" -eq 1 # fixtures hold real changes
Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
shell: bash
run: |
set +e
python -m compare_tool tests/fixtures/old tests/fixtures/new --report report.html
python -m compare_tool tests/fixtures/demo/old tests/fixtures/demo/new --report report.html
code=$?
set -e
test "$code" -eq 1 # fixtures contain real changes -> exit code 1 expected
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ All notable changes to this project are documented here. Versions follow

## [Unreleased]

### Added

- **Fold and resize the panes in the viewer's left column.** The folder tree,
the quick-changes rollup and the consistency heads-up each have a bar you can
click to fold that pane away and give its height to the others; click again
and it comes back the size you left it. All three can be dragged, including
the heads-up pane, which was previously pinned at a fixed height.

### Changed

- **Turning off Comment or Unimportant no longer reports those files as
Identical.** Their lines still grey out and drop off the minimap and F7/F8,
but the file keeps its real verdict everywhere — in the tree, in the counts
and in an exported report. `Hide identical` follows suit and hides only files
that genuinely have no difference. Previously a file whose comments really
had moved could read as Identical on screen while the exported report said
otherwise.
- Improve how the two noise verdicts are marked in the tree, so the report and
the viewer no longer show the same file differently.

## [1.11.0] — 2026-08-22

### Added
Expand Down
24 changes: 18 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,24 @@ place, `diff_engine._status_of`.
Only noise verdicts are foldable (`scanner.FOLDABLE`). `real-change`, `added`,
`deleted` and `error` can **never** be folded away by a UI toggle.

Folding a category in the viewer changes the file's verdict and **greys** its
rows (`view_model.mute_rows`) — it does not remove them. The lines stay
readable, and only the "where should I look next" surfaces (minimap, F7/F8)
stop counting them. Collapsing them to a `⋯ N lines hidden` placeholder was
tried and reverted: a regenerated file is mostly banner churn, so it took the
context the surviving hunks have to be read in.
**A viewer toggle never changes a verdict.** Unticking `Comment` or
`Unimportant` **greys** those rows (`view_model.mute_rows`) and drops them from
the minimap and `F7`/`F8` — nothing else. The file keeps saying Comment, the
counts keep counting it, and `Hide identical` still leaves it in the tree,
because it is not identical. Re-judging it to `identical` is what the viewer
used to do, and it was wrong twice over: the tree then disagreed with the
exported report about the same file, and "Identical" is the one word a reviewer
is entitled to read as *nothing differs here at all*.

Removing those rows instead of greying them was tried and reverted too: a
regenerated file is mostly banner churn, so a `⋯ N lines hidden` placeholder
took away the context the surviving hunks have to be read in.

Both noise verdicts wear the same `≈` mark, in the report's tree and the
viewer's alike — they are one answer to "must I read this?", and the label
beside the mark says which kind of nothing it is. The mark lives once, in
`view_model.VERDICT_MARK`: the two trees each kept a copy and drifted, so the
same file read `≉` in one and `≈` in the other.

## 3. One seam per shared decision

Expand Down
42 changes: 19 additions & 23 deletions compare_tool/qtviewer/advisories.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Consistency advisories under the quick-changes panel: the same cross-artifact
and cross-model heads-up the HTML report and the CLI print, shown live in the
viewer's bottom-left.
"""Consistency advisories: the same cross-artifact and cross-model heads-up
the HTML report and the CLI print, shown live in the viewer's Consistency
section (last of the three panes in the left column).

Display only, exactly like the report's block -- it names the model and the
caution, never folds a file, moves a count or changes the exit code. The text
Expand All @@ -19,38 +19,38 @@


class AdvisoryPanel(QFrame):
"""Pinned strip at the very bottom of the left column. Hidden outright when
there is nothing to say, so a clean compare spends no height on it."""
"""Body of the left column's Consistency section. Hidden outright when
there is nothing to say, so a clean compare spends no height on it -- the
section around it goes with it (see MainWindow._show_advisories)."""

def __init__(self):
super().__init__()
self.setObjectName('advisorypanel')
self._advisories = []

self._header = QLabel()
self._header.setObjectName('advisoryhead')

self._body = QLabel()
self._body.setWordWrap(True)
self._body.setAlignment(Qt.AlignTop)
# the messages carry file/model names a reviewer may want to copy into a
# ticket, and selection never triggers navigation
self._body.setTextInteractionFlags(Qt.TextSelectableByMouse)

# bounded height: a folder full of stale models must not eat the tree
# above it, so past a few rows the strip scrolls instead of growing
# the pane is a section the reviewer can drag, so the height is theirs
# to set: the panel fills whatever it is given and scrolls past that.
# It used to be capped at 120px from the days it was pinned under the
# splitter and could not be resized -- with the cap still in, opening
# this pane alone left the text stranded in the middle of an empty
# panel with the rest of the height unused.
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QFrame.NoFrame)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setMaximumHeight(120)
scroll.setWidget(self._body)

lay = QVBoxLayout(self)
lay.setContentsMargins(8, 6, 8, 8)
lay.setSpacing(4)
lay.addWidget(self._header)
lay.addWidget(scroll)
lay.addWidget(scroll, 1)
self.setVisible(False)

def set_advisories(self, advisories):
Expand All @@ -61,19 +61,15 @@ def set_advisories(self, advisories):
if not self._advisories:
self.setVisible(False)
return
n = len(self._advisories)
self._header.setText('⚠ Consistency — {} heads-up{}'.format(
n, '' if n == 1 else 's'))
# apply_theme owns both the header style and the body render, so the
# first show is painted in the current theme without a separate init call
self.apply_theme()
# no heading of its own: the section bar above already says
# "CONSISTENCY 2 heads-ups", and repeating it here spends a row of a
# narrow panel restating what the reviewer just read
self.apply_theme() # paints the body in the current theme
self.setVisible(True)

def apply_theme(self):
"""Colours are stamped per label, so a theme switch has to repaint them
from the advisories the panel was last given."""
self._header.setStyleSheet(
'color:{}; font-weight:bold;'.format(theme.c('mv-fg')))
"""Colours are stamped into the body's markup, so a theme switch has to
re-render it from the advisories the panel was last given."""
self._render()

def _render(self):
Expand Down
Loading