CAMEL-23237: camel-jbang catalog tables fill the terminal width#24386
CAMEL-23237: camel-jbang catalog tables fill the terminal width#24386ammachado wants to merge 4 commits into
Conversation
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 8 tested, 8 compile-only — current: 6 all testedMaveniverse Scalpel detected 16 affected modules (current approach: 6).
|
gnodet
left a comment
There was a problem hiding this comment.
Nice work, @ammachado — this is a well-structured improvement to the catalog table rendering. The new CamelTableColumns toolkit centralizes what was previously hand-rolled in every command with differing widths, and the noBorderOverhead bug fix (from (n-1)*2 to n*2) is correct — AsciiTable NO_BORDERS pads every column with one leading and one trailing space.
The test coverage is good: CamelTableColumnsTest covers measure(), lastColumnWidth(), and the rendering-level regression test that verifies tables don't overflow the terminal width. The TerminalWidthHelperTest additions for parseColumns, fillWidth, and the localized Windows mode con output are thorough.
A few observations:
1. [observation] DEFAULT_WIDTH change from 120 to 80
This is documented in the upgrade guide, which is good. Worth noting that this changes the behavior for all existing callers of getTerminalWidth() that fall back to the default — not just the catalog commands. Any table/command that previously got 120 as the fallback will now get 80, which may truncate more aggressively when output is piped or redirected. The PR description says this is intentional ("the standard fallback when no terminal can be detected"), and 80 is indeed the standard terminal width assumption. Just flagging it since it's a cross-cutting default change.
2. [nit] parseColumns assumes column count is always the second integer
This works for both stty size ("rows cols") and English/French mode con output. However, some Windows locales or non-standard mode con output might have the integers in a different order (e.g., if a header line contains a number before the "Lines" field). The positional approach is pragmatic — label parsing would be fragile across locales — but worth documenting this assumption in the Javadoc (which it already does, so this is fine).
3. [positive] Bug fix in noBorderOverhead is backward-compatible
The fix changes the formula but all existing callers used flexWidth() which clamps to [min, max], so the 2-column shift only matters for the new uncapped fillWidth(). Nice that the PR identified and fixed this proactively.
CI: The failures (UpdateListTest.listUpdateVersions) are in version-update listing, unrelated to this PR's catalog table changes. Appears to be a pre-existing flaky test.
Note: this review does not replace specialized tools such as CodeRabbit, Sourcery, or SonarCloud.
Reviewed with Claude Code on behalf of Guillaume Nodet (@gnodet). This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
oscerd
left a comment
There was a problem hiding this comment.
Thanks @ammachado — filling the DESCRIPTION column to the terminal width is a real improvement, the off-by-2 noBorderOverhead fix is correct, and I like that it's now backed by a rendering-level regression test (CamelTableColumnsTest.lastColumnWidthKeepsRenderedTableWithinTerminal) instead of an arithmetic-only assertion. There's a blocking CI regression though, so I'm requesting changes.
Blocker: the shared width change breaks UpdateListTest (deterministic, in CI)
This PR changes two things in the shared TerminalWidthHelper:
DEFAULT_WIDTH120 → 80 (the no-TTY / piped fallback)noBorderOverhead(n)from(columnCount - 1) * 2tocolumnCount * 2
But UpdateList (commands/update/UpdateList.java) was intentionally left for follow-up and still calls flexWidth(terminalWidth(), 45, noBorderOverhead(4), 20, 80). In CI there is no TTY, so terminalWidth() returns the fallback, and the DESCRIPTION column width collapses:
- before:
max(20, min(80, 120 − 45 − 6)) = 69→ the 43-char description fits on one line - after:
max(20, min(80, 80 − 45 − 8)) = 27→ the description word-wraps
UpdateListTest.listUpdateVersions (line 37) asserts .contains("Migrates Camel 4 application to Camel 4.9.0"), and that contiguous string no longer exists once the column wraps. The CI log confirms it: build (17, false) fails deterministically (through all surefire reruns) at UpdateListTest.listUpdateVersions:37, with the rendered table showing the wrapped Migrates Camel 4 … description. build (25, false) is the matrix cancel-cascade of the same failure.
Suggested fix
Either migrate UpdateList in this PR as well, or make UpdateListTest width-robust (e.g. pin COLUMNS, or assert against a wrap-tolerant substring).
Blast-radius note (non-blocking)
Lowering DEFAULT_WIDTH 120 → 80 narrows the piped/redirected fallback for every not-yet-migrated NO_BORDERS table, not only the catalog commands — UpdateList is just the one with a test pinning the old width. Worth a quick scan of the other process/action snapshot tests for the same coupling before the follow-up migration lands.
Everything else looks good — the upgrade-guide entry is clear and the new tests are strong. Once CI is green this should be an easy re-review.
Reviewed with Claude Code on behalf of Andrea Cosentino (@oscerd). This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
davsclaus
left a comment
There was a problem hiding this comment.
80 width is way to small today
|
The rationale for 80-column width is that this is (or was) the default width for the Windows Command Prompt terminal. I'll revert this change. |
Standardize column definitions and expand the last free-text column (DESCRIPTION) of the catalog tables to the terminal width instead of capping it at 80, like gh/ps/systemctl. - Add common/CamelTableColumns toolkit: name()/since()/lastText() column factories plus measure() and lastColumnWidth() so the last column gets the exact remaining width. measure() mirrors freva's String.length() sizing so the remainder math matches what AsciiTable renders. - TerminalWidthHelper: add Windows mode con detection, add fillWidth() (no upper cap), change DEFAULT_WIDTH 120 -> 80, extract package-private parseColumns(). - Migrate CatalogBaseCommand, CatalogTransformer (drop the nameWidth()=60 override) and CatalogKamelet onto the toolkit. CatalogDoc left as-is (detail view with FANCY_ASCII + scaleWidth + NEWLINE wrapping). - --json remains the lossless path for automation; TTY output stays fit-to-terminal and ellipsis-truncated. Process and action command tables migrate in follow-up work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…in the terminal noBorderOverhead(n) returned (n-1)*2, but AsciiTable NO_BORDERS pads every column with one leading and one trailing space, so the real overhead is n*2. This was harmless while every table used capped flexWidth, but the new uncapped fillWidth/lastColumnWidth sizes the last column to the exact remainder, so the 2-column underestimate made the widest rows render at terminalWidth + 2 and soft-wrap. Fixed at the root (noBorderOverhead now returns n*2), which is safe for all existing flexWidth callers because they clamp their result to [min, max]; the change only ever removes a latent 2-column overflow. Updated the existing overhead assertions and added a rendering-level regression test that asserts a lastColumnWidth-sized NO_BORDERS table never exceeds the terminal width (arithmetic-only tests missed the off-by-2 because they encoded the same wrong value). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…the table toolkit Address PR review feedback: - Revert DEFAULT_WIDTH from 80 back to 120. 80 is too narrow for today's terminals (davsclaus, gnodet), and lowering the shared no-TTY fallback narrowed every not-yet-migrated NO_BORDERS table, not just the catalog commands. - Migrate UpdateList onto CamelTableColumns: measure the actual rendered width of VERSION / RUNTIME / RUNTIME VERSION and size DESCRIPTION to fill the terminal via lastColumnWidth(), instead of the hand-rolled capped flexWidth. This is the structural fix for the UpdateListTest CI failure (oscerd): the DESCRIPTION column is now sized from measured widths rather than depending on the shared fallback constant. Dropped VERSION's minWidth(10) so the measured width equals the rendered width, which the fill math requires. - Update the 4.22 upgrade guide to state the 120-column fallback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
davsclaus
left a comment
There was a problem hiding this comment.
Review: CAMEL-23237 — camel-jbang catalog tables fill the terminal width
Blocking Issue
1. Merge conflicts — The PR currently has CONFLICTING merge state. It needs a rebase onto main before CI can run and the changes can be verified.
Prior Review Status
The two prior CHANGES_REQUESTED reviews from @oscerd and @davsclaus appear to be addressed by commit a70d811 (reverts DEFAULT_WIDTH back to 120 and migrates UpdateList onto the CamelTableColumns toolkit). However, because of the merge conflict, CI cannot verify this.
Confirmed Findings
2. noBorderOverhead formula change is cross-cutting (non-blocking, informational)
The fix from (columnCount - 1) * 2 to columnCount * 2 is correct — AsciiTable NO_BORDERS pads every column with 1 leading + 1 trailing space. However, this affects ~30 existing callers across CamelMemoryLeak, CamelThreadDump, CamelSpanAction, LoggerAction, CamelHistoryAction, CamelBrowseAction, CamelBeanDump, CamelProcessorStatus, CamelRouteStatus, MessageTableHelper, etc.
The PR description states this is safe because all existing callers use flexWidth() which clamps to [min, max]. This is correct — the 2-column shift only becomes visible at mid-range terminal widths (where flex columns may render 2 chars narrower), and is actually a fix for the previous 2-char overflow. Worth noting for posterity but not blocking.
Questions / Observations
3. InfraBaseCommand still uses old pattern — InfraBaseCommand.java (line 213-214) calls flexWidth(...) with hand-rolled fixed column widths but was not migrated to the new CamelTableColumns toolkit. This is fine as follow-up work, but if the contributor wants this PR to be the single source of truth for catalog-style tables, InfraBaseCommand follows the same pattern.
4. Test coverage is good — CamelTableColumnsTest covers measure(), lastColumnWidth(), and importantly includes a rendering-level regression test that renders an actual AsciiTable and verifies all lines fit within the terminal width. TerminalWidthHelperTest additions for parseColumns, fillWidth, and localized Windows mode con output are thorough.
5. Upgrade guide entry — Present, clear, and appropriately scoped under the camel-jbang section. Documents the behavior change and recommends --json for scripting.
6. AI attribution — Properly disclosed in PR body and commit trailers.
Summary
This is a well-structured improvement. The CamelTableColumns toolkit centralizes duplicated column definitions, the noBorderOverhead fix is correct, and the adaptive column measurement via measure() is better than the previous hardcoded width guessing. The main action needed is resolving the merge conflict and getting CI green.
This review does not replace specialized tools such as CodeRabbit, Sourcery, or SonarCloud.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
…s toolkit Follow the same terminal-filling model as the catalog tables (review follow-up from @davsclaus): - DESCRIPTION now fills the terminal width via CamelTableColumns; the other columns are measured so it gets the exact remainder. - IMPLEMENTATION is capped and SERVICE_DATA keeps a compact fixed width; both truncate with an ellipsis (ELLIPSIS_RIGHT) instead of letting the raw JSON service data overflow and soft-wrap the terminal. Full, structured service data is still available via --json. Also extract the --json service-data handling into a testable parseServiceData() helper and cover it with two tests: - serviceData is embedded as nested JSON (not an escaped string) in --json - unparseable service data is dropped rather than emitted, and no longer risks an NPE when there is no data (added an explicit null guard). Documented the infra list display change in the 4.22 upgrade guide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Following up on @davsclaus's review, specifically the
One design question for reviewers before considering this settled:
Claude Code on behalf of Adriano Machado. |
davsclaus
left a comment
There was a problem hiding this comment.
Nice work on this PR — the measured-column approach and the CamelTableColumns toolkit are a solid improvement over the hand-rolled per-command widths.
A few observations (none blocking):
- The
noBorderOverheadfix from(n-1)*2ton*2is correct per AsciiTable's padding model. All ~50 existingflexWidthcallers are safe because they clamp to[min, max], absorbing the 2-column reduction. - The positional
parseColumns()approach ("take the second integer") is robust for bothstty sizeand localizedmode conoutput — good call avoiding label-based parsing. - The rendering-level regression test (
lastColumnWidthKeepsRenderedTableWithinTerminal) directly validates the claim that sized tables don't overflow — that's the right test to have. - Scope is well-bounded: migrating
process/andaction/commands can be follow-up work.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Description
The
camel catalogcommands (component,dataformat,language,transformer,kamelet, ...) previously truncated theDESCRIPTIONcolumn at a fixed 80 characters regardless of terminal size, and each command hand-rolled its column definitions with inconsistent widths (NAMEwas 60 fortransformerand 30 elsewhere).This PR sizes the last free-text column to fill the detected terminal width and standardizes the shared column definitions.
Changes:
common/CamelTableColumns.javatoolkit:name(),since(),lastText(),measure(),lastColumnWidth().measure()computes a column's actual rendered width (header vs. longest cell, capped);lastColumnWidth()gives the remaining terminal width to the last column and truncates it with an ellipsis so each row stays on one line.TerminalWidthHelper:fillWidth()(no upper cap, unlikeflexWidth()).cmd/PowerShell) viamode con, in addition to the existingCOLUMNS/stty sizedetection. Column parsing is positional (second integer) so it survives localized Windows output where theColumns:label is translated.DEFAULT_WIDTHstays at 120 (the fallback when no terminal can be detected, e.g. piped/redirected output).CatalogBaseCommand,CatalogTransformer(dropped itsnameWidth()override),CatalogKamelet,UpdateList, andInfraBaseCommand(camel infra list) onto the toolkit.--json.Follow-up fix included in this PR (found during self-review):
noBorderOverhead(n)returned(n-1)*2, butAsciiTableNO_BORDERSpads every column with one leading and one trailing space, so the real overhead isn*2. This was harmless while every table used cappedflexWidth, but the new uncapped fill sizes the last column to the exact remainder, so the 2-column underestimate made the widest rows render atterminalWidth + 2and soft-wrap. Fixed at the root (safe for all existingflexWidthcallers, which clamp to[min, max]) and covered by a new rendering-level regression test.Review updates:
DEFAULT_WIDTHfrom 120 to 80; that shared-default change is reverted (80 is too narrow for modern terminals, and it narrowed the no-TTY fallback for every not-yet-migratedNO_BORDERStable).UpdateListis now migrated onto the toolkit rather than left as follow-up, which is the structural fix for the previousUpdateListTestCI failure: itsDESCRIPTIONcolumn is sized from measured column widths instead of the shared fallback constant.camel infra list(InfraBaseCommand) is now migrated too:DESCRIPTIONfills the terminal, andIMPLEMENTATION/SERVICE_DATAtruncate with an ellipsis instead of letting the raw JSON service data overflow the terminal. The--jsonservice-data handling was extracted into a testableparseServiceData()helper (embedded as nested JSON, not an escaped string; unparseable data is omitted rather than emitted, and no longer risks an NPE on missing data), covered by two newInfraTestcases.Target
mainbranch)Tracking
CAMEL-23237
Apache Camel coding standards and style
mvn clean install -DskipTestslocally from root folder and I have committed all auto-generated changes.AI-assisted contributions
Co-authored-bytrailers) and the PR description identifies the AI tool used.AI-assisted with Claude Code (Claude Opus 4.8) on behalf of Adriano Machado.