fix(show): star marker, aligned gutter and smarter AUR merge

N?? / show marks the upstream candidate with "*" instead of ">" (the
prompt, which read as a command in logs), and every line but the note
gets a two-character gutter: "  " for the installed record, "* " for the
candidate, so keys and colons line up. The plain native fallback (zypper,
unmergeable records) and the not-installed candidate use the same gutter.

pacman records (-Qi with -Si or the AUR helper's -Sia) are now compared
the way they are meant:
- values unwrapped (continuation lines joined, runs of blanks as one):
  yay wraps Depends On / Optional Deps at 80 columns even without a
  terminal unless COLUMNS=0, which the helper now gets for -Qua and -Sia
- Depends On, Provides, Conflicts With, Make/Check Deps and the other
  lists as sets of exact tokens in any order (a constraint is a change)
- Optional Deps by package names ("name: description [installed]" in
  -Qi, bare names from the AUR)
- a differing value is one line like -Qi, Optional Deps one entry per
  line; candidate-only fields sit next to their counterpart (Repository
  after Version, AUR URL after URL, Maintainer after Packager, ...)

Verified on recorded claude-desktop records (paru 2.1.0, yay 13.0.1, the
installed 2.9939.4-1 from the AUR's own .SRCINFO); discovery/pacman.md
section 15.2.
This commit is contained in:
bryanpedini committed 2026-10-10 16:01:51 +02:00
1 parent def537af58
commit 3af159e09a
16 files changed
+680 -288

No files matched your search

+44 -13
View File
@@ -170,31 +170,62 @@ history by itself). readline draws the prompt and the line on stderr, as bash do
stdin keeps the plain `IFS= read -r` with the prompt on stdout and each line echoed after it, so
piped runs and their logs are unchanged.
Full info (`N??`, `show PKG`). The first line is `# lines starting with > come from the upstream
candidate: a differing value, or a field the installed record lacks`; then the installed record in
its native key/value layout, as the base. After each field whose candidate value differs, the
candidate's line follows, prefixed with `> ` (same key formatting); fields only the candidate has
are appended at the end the same way; fields only the installed record has stay; identical fields
print once. A field starts on a line that begins with a non-blank character and holds a `:` (the
key is the text before it); lines beginning with a blank continue it, so multi-line values (pacman
`Optional Deps`, dnf `Description`, RFC-822 continuation lines) are compared as blocks, every line
trimmed, and a differing candidate block gets `> ` on every line. `Description-xx` (apt Translation
Full info (`N??`, `show PKG`). The first line is `# lines starting with * come from the upstream
candidate: a differing value, or a field the installed record lacks` (no gutter); every other line
starts with a two-character gutter, ` ` for the installed record and its continuation lines, `* `
for the candidate's lines and theirs, so keys and colons line up. Then the installed record in its
native key/value layout, as the base. After each field whose candidate value differs, the
candidate's line follows, marked `* ` (same key formatting); fields only the candidate has are
appended at the end the same way (pacman: placed next to their counterpart, below); fields only the
installed record has stay; identical fields print once. A field starts on a line that begins with a
non-blank character and holds a `:` (the key is the text before it); lines beginning with a blank
continue it, so multi-line values (pacman `Optional Deps`, dnf `Description`, RFC-822 continuation
lines) are compared as blocks, every line trimmed, and a differing candidate block gets `* ` on every
line. `Description-xx` (apt Translation
files) pairs with `Description`; on apt a one-line candidate `Description` equal to the first
installed line counts as identical (the archives carry only the short description, the long text
is in the Translation files). When both records align their `:` in one column but in different
ones (dnf5: 16 installed, 15 available), the candidate lines are re-padded to the installed one's.
ones (dnf5: 16 installed, 15 available; yay's AUR records: 30), the candidate lines are re-padded to
the installed one's.
pacman (`-Qi` with `-Si REPO/PKG` or `<helper> -Sia PKG`, `discovery/pacman.md` sections 14-15):
- values are compared unwrapped - continuation lines joined to their key on both sides, runs of
blanks as one blank - because the AUR helpers wrap long lists at the terminal width;
- `Groups`, `Provides`, `Depends On`, `Required By`, `Optional For`, `Conflicts With`, `Replaces`,
`Make Deps`, `Check Deps`, `Licenses`, `Keywords`: as sets of exact tokens, in any order (a version
constraint is part of its token, so a changed constraint is a difference);
- `Optional Deps`: as sets of package names - `: description` and ` [installed]` stripped (`-Qi`
prints `name: description [installed]` per line, the AUR records bare names separated by blanks);
- a differing candidate value is printed on one line, as `-Qi` prints every field (an unwrapped
helper value is joined with two blanks for the lists above, one otherwise; a one-line value stays
as it is); `Optional Deps`, one entry per line in `-Qi`, gets one entry per line under the value
column;
- candidate-only fields go next to their installed counterpart, in this order, the others at the end
in the candidate's order:
| candidate field | right after |
|-----------------|-------------|
| `Repository` | `Version` |
| `AUR URL` | `URL` |
| `Keywords` | `Groups` |
| `Make Deps`, `Check Deps` | `Optional Deps` |
| `Maintainer` | `Packager` |
| `Last Modified`, `First Submitted` | `Build Date` |
| `Download Size` | `Installed Size` |
| backend | installed record | upstream candidate |
|---------|------------------|--------------------|
| pacman | `pacman -Qi PKG` | `pacman -Si REPO/PKG`, REPO = the first repository `pacman -Sl` lists PKG in (as for the review list); a package in no repository: the AUR record, `<helper> -Sia PKG`, when a helper is in use (should it not merge, `pacman -Qi` is followed by the AUR record with every line marked `> `) |
| pacman | `pacman -Qi PKG` | `pacman -Si REPO/PKG`, REPO = the first repository `pacman -Sl` lists PKG in (as for the review list); a package in no repository: the AUR record, `<helper> -Sia PKG`, when a helper is in use (should it not merge, `pacman -Qi` is followed by the AUR record with every line marked `* `) |
| apt | `dpkg-query -s PKG` (Status, Conffiles, always the long description; `apt-cache show PKG=<installed>` gives the archive's record when that version is still listed: no Status/Conffiles, short description only); a `Status` of `not-installed`/`config-files` = not installed | `apt-cache show --no-all-versions PKG` |
| dnf | `dnf -q info --installed PKG` | `dnf -q info --upgrades PKG` (installed architecture only; `--available` also lists other architectures and, for an up-to-date package, other builds); not installed: `--available` |
| zypper | - | - (`rpm -qi` and `zypper info` share almost no keys - Version vs version-release, Arch, byte sizes, source names, description layout - and zypper cannot print the installed record by itself: `zypper info -r @System` is refused) |
A package that is not installed (a row whose old version is `-` is not asked) shows the candidate
alone under `# not installed: this is the upstream candidate`. Anything else - no candidate (an
alone, every line marked `* `, under `# not installed: lines starting with * come from the upstream
candidate (all of them)`. Anything else - no candidate (an
up-to-date dnf package, a local-only pacman package), not exactly one record on each side (two
installed architectures), zypper - prints `<be>_full_info` unchanged. `dnf info` headings
installed architectures), zypper - prints `<be>_full_info` as it is (in the " " gutter). `dnf info` headings
("Installed Packages", ...) are dropped. Verified formats: `discovery/{pacman,apt,rpm}.md`.
Flags shown after a row: `[held]` = the package manager will not upgrade it on its own: on apt