Skip to content

feat(format): add WidthStrategy interface for pluggable column width algorithms#569

Merged
apstndb merged 7 commits intomainfrom
issue-566-width-strategy-interface
Mar 17, 2026
Merged

feat(format): add WidthStrategy interface for pluggable column width algorithms#569
apstndb merged 7 commits intomainfrom
issue-566-width-strategy-interface

Conversation

@apstndb
Copy link
Owner

@apstndb apstndb commented Mar 16, 2026

Summary

Extract the monolithic calculateOptimalWidth() behind a WidthStrategy interface, enabling runtime selection of column width algorithms via the CLI_WIDTH_STRATEGY system variable. This is a prerequisite for #567 (NoWrapCell).

Three strategies are implemented:

  • GREEDY_FREQUENCY (default, zero value): existing frequency-based greedy expansion — unchanged behavior
  • PROPORTIONAL: deficit-proportional allocation based on natural column width
  • MARGINAL_COST: wrap-line minimization via max-heap (container/heap)

Key Changes

  • enums/enums.go: Add WidthStrategy enum with go:generate directive
  • internal/mycli/format/width_strategy.go: Define WidthStrategy interface, ColumnHint struct (with NoWrap reserved for Introduce NoWrapCell to generalize minColumnWidth hardcoding #567), and NewWidthStrategy factory
  • internal/mycli/format/width_strategy_greedy.go: Extract existing calculateOptimalWidth() body into GreedyFrequencyStrategy.CalculateWidths()
  • internal/mycli/format/width_strategy_proportional.go: New ProportionalStrategy — allocates proportionally to each column's deficit from natural width
  • internal/mycli/format/width_strategy_marginal.go: New MarginalCostStrategy — greedy heap-based wrap-line minimization, O(availableWidth * log(numCols))
  • internal/mycli/format/width.go: calculateOptimalWidth() replaced by thin CalculateWidthWithStrategy() that computes overhead, creates hints, delegates to strategy. Also fixes header double-counting: verboseHeaders are now passed as headers to strategies (counted once), instead of being prepended to rows and re-added by each strategy.
  • internal/mycli/format/config.go: Add WidthStrategy enums.WidthStrategy to FormatConfig
  • internal/mycli/format/streaming_table.go: Wire strategy from config into calculateWidths()
  • internal/mycli/system_variables.go: Add WidthStrategy to DisplayVars, wire in toFormatConfig()
  • internal/mycli/var_enum_handlers.go: Add WidthStrategyVar() helper
  • internal/mycli/var_registry.go: Register CLI_WIDTH_STRATEGY system variable

Bug Fix: Header Double-Counting

The original calculateOptimalWidth() prepended verboseHeaders to rows, then re-added columnNames to the data inside the algorithm via hiter.Concat(hiter.Once(StringsToRow(header...)), ...). This caused headers to be counted twice in width calculations (especially in non-verbose mode where verboseHeaders == columnNames).

Fixed by passing verboseHeaders as the headers parameter to strategies (which include them exactly once in their data), without prepending to rows. In verbose mode, adjustByHeader now correctly uses verbose header display widths for initial proportional allocation.

Test Plan

  • make check passes (test + lint + fmt-check)
  • Existing width_test.go tests pass unchanged (regression safety)
  • TestCompareStrategies logs meaningful output for all 3 strategies
  • TestStrategyMinColumnWidth ensures all strategies respect minColumnWidth
  • TestSystemVariables_EnumTypes/WidthStrategy tests SET with all values, case insensitivity, and invalid value rejection
  • Benchmarks show reasonable performance for all strategies

Fixes #566

apstndb and others added 2 commits March 17, 2026 03:30
…ms (#566)

Extract the monolithic calculateOptimalWidth() behind a WidthStrategy
interface, enabling runtime selection of column width algorithms via
the CLI_WIDTH_STRATEGY system variable.

Three strategies are implemented:
- GREEDY_FREQUENCY (default): existing frequency-based greedy expansion
- PROPORTIONAL: deficit-proportional allocation based on natural width
- MARGINAL_COST: wrap-line minimization via max-heap (container/heap)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add enum-type tests for CLI_WIDTH_STRATEGY covering all values
(GREEDY_FREQUENCY, PROPORTIONAL, MARGINAL_COST), case insensitivity,
and invalid value rejection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apstndb apstndb added enhancement New feature or request refactoring labels Mar 16, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the table formatting capabilities by introducing a flexible and extensible architecture for column width allocation. It abstracts the width calculation logic behind an interface, allowing different algorithms to be plugged in and selected at runtime. This change not only provides more control over table rendering but also lays the groundwork for future features like non-wrapping columns, improving the overall user experience and maintainability of the formatting subsystem.

Highlights

  • Pluggable Column Width Algorithms: Introduced a WidthStrategy interface to allow runtime selection of column width algorithms, addressing a prerequisite for Introduce NoWrapCell to generalize minColumnWidth hardcoding #567 (NoWrapCell).
  • New Width Strategies Implemented: Implemented three distinct strategies: GREEDY_FREQUENCY (the existing default behavior), PROPORTIONAL (deficit-proportional allocation), and MARGINAL_COST (wrap-line minimization using a max-heap).
  • System Variable Integration: Added CLI_WIDTH_STRATEGY as a new system variable, enabling users to configure the desired width allocation algorithm via the CLI.
  • Refactored Width Calculation Logic: The monolithic calculateOptimalWidth() function was refactored to delegate to the new WidthStrategy interface, improving modularity and extensibility.
Changelog
  • enums/enums.go
    • Added WidthStrategy enum type with GreedyFrequency, Proportional, and MarginalCost values.
    • Included go:generate directive for enum code generation.
  • enums/widthstrategy_enumer.go
    • Generated Go code for the WidthStrategy enum, including String(), WidthStrategyString(), and WidthStrategyValues() methods.
  • internal/mycli/format/config.go
    • Imported the new enums package.
    • Added WidthStrategy field to FormatConfig struct to store the selected column width algorithm.
  • internal/mycli/format/streaming_table.go
    • Modified calculateWidths to call CalculateWidthWithStrategy, passing the configured WidthStrategy.
  • internal/mycli/format/width.go
    • Removed fmt import as it's no longer directly used in the refactored logic.
    • Updated CalculateWidth to call CalculateWidthWithStrategy with WidthStrategyGreedyFrequency as the default.
    • Replaced the original calculateOptimalWidth function with CalculateWidthWithStrategy, which now computes overhead, creates hints, and delegates to the appropriate WidthStrategy implementation.
  • internal/mycli/format/width_strategy.go
    • Added ColumnHint struct for per-column metadata, including a NoWrap field reserved for future use.
    • Defined the WidthStrategy interface with a CalculateWidths method.
    • Implemented NewWidthStrategy factory function to return the correct strategy based on the WidthStrategy enum value.
  • internal/mycli/format/width_strategy_bench_test.go
    • Added new benchmark tests for WidthStrategy implementations, covering small, medium, and large datasets.
  • internal/mycli/format/width_strategy_greedy.go
    • Implemented GreedyFrequencyStrategy which encapsulates the original frequency-based greedy expansion algorithm for column width calculation.
  • internal/mycli/format/width_strategy_marginal.go
    • Implemented MarginalCostStrategy to minimize total wrap-lines using a greedy max-heap approach, with helper functions for calculating wrap lines and managing the heap.
  • internal/mycli/format/width_strategy_proportional.go
    • Implemented ProportionalStrategy to allocate column widths proportionally to their natural width, distributing remaining space based on deficit.
  • internal/mycli/format/width_strategy_test.go
    • Added unit tests for GreedyFrequencyStrategy, ProportionalStrategy, MarginalCostStrategy, and NewWidthStrategy.
    • Included TestCompareStrategies to log and compare outputs of different strategies, and TestStrategyMinColumnWidth to ensure minimum width adherence.
  • internal/mycli/system_variables.go
    • Added WidthStrategy field to DisplayVars struct.
    • Mapped the Display.WidthStrategy to format.FormatConfig.WidthStrategy in the toFormatConfig() method.
  • internal/mycli/system_variables_test.go
    • Imported enums package for WidthStrategy enum.
    • Added a new test suite for WidthStrategy enum types, verifying valid and invalid value parsing and case insensitivity.
    • Included CLI_WIDTH_STRATEGY in TestSystemVariables_SetGetOperations string tests.
  • internal/mycli/var_enum_handlers.go
    • Added WidthStrategyVar helper function to create an enum handler for the WidthStrategy type.
  • internal/mycli/var_registry.go
    • Registered the new CLI_WIDTH_STRATEGY system variable with its description and associated enum handler.
Activity
  • The author provided benchmark results on an Apple M2, showing performance characteristics for small, medium, and large datasets across all three width strategies.
  • A comparison of strategies was logged, demonstrating how each algorithm produces different width allocations and total wrap counts.
  • A comprehensive test plan was outlined and executed, including make check, existing regression tests, new strategy-specific tests, and system variable tests for CLI_WIDTH_STRATEGY.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively refactors the column width calculation logic by introducing a WidthStrategy interface. This is a great improvement for extensibility, allowing different width allocation algorithms to be plugged in and selected at runtime. The addition of Proportional and MarginalCost strategies alongside the existing GreedyFrequency logic is well-implemented, and the new CLI_WIDTH_STRATEGY system variable is correctly wired up. The accompanying tests and benchmarks are thorough.

My main feedback is on code organization within the new strategy files, where some utility functions are misplaced, impacting maintainability. Please see the specific comment for details.

@github-actions
Copy link

github-actions bot commented Mar 16, 2026

Code Metrics Report

📊 View detailed coverage report (available for 7 days)

main (f78f61c) #569 (271ce71) +/-
Coverage 70.0% 70.5% +0.4%
Code to Test Ratio 1:1.2 1:1.2 -0.1
Test Execution Time 2m9s 1m27s -42s
Details
  |                     | main (f78f61c) | #569 (271ce71) |  +/-  |
  |---------------------|----------------|----------------|-------|
+ | Coverage            |          70.0% |          70.5% | +0.4% |
  |   Files             |             70 |             74 |    +4 |
  |   Lines             |           6800 |           6921 |  +121 |
+ |   Covered           |           4765 |           4883 |  +118 |
- | Code to Test Ratio  |          1:1.2 |          1:1.2 |  -0.1 |
  |   Code              |          15840 |          16137 |  +297 |
+ |   Test              |          20504 |          20769 |  +265 |
+ | Test Execution Time |           2m9s |          1m27s |  -42s |

Code coverage of files in pull request scope (87.7% → 89.3%)

Files Coverage +/- Status
enums/enums.go 0.0% 0.0% modified
internal/mycli/format/config.go 100.0% 0.0% modified
internal/mycli/format/streaming_table.go 78.3% 0.0% modified
internal/mycli/format/width.go 96.0% -1.7% modified
internal/mycli/format/width_strategy.go 100.0% +100.0% added
internal/mycli/format/width_strategy_greedy.go 100.0% +100.0% added
internal/mycli/format/width_strategy_marginal.go 96.4% +96.4% added
internal/mycli/format/width_strategy_proportional.go 100.0% +100.0% added
internal/mycli/system_variables.go 93.9% 0.0% modified
internal/mycli/var_enum_handlers.go 75.6% +0.3% modified
internal/mycli/var_registry.go 86.8% +0.0% modified

Reported by octocov

Move wrapLinesForWidth and splitLines from width_strategy_proportional.go
to width.go since they are shared by MarginalCostStrategy and tests.
Replace custom indexOf with strings.IndexByte per review feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apstndb
Copy link
Owner Author

apstndb commented Mar 16, 2026

Performance improvement notes for future work

Analysis of iter/lo usage across the three strategies identified several optimization opportunities for the GreedyFrequency strategy (carried over from the original calculateOptimalWidth).

Where iter helps (keep as-is)

  • splitLines as iter.Seq[string]: Avoids []string allocation from strings.Split. Consumed directly via for line := range splitLines(s) in wrapLinesForWidth. This contributes to MarginalCostStrategy's low allocation count (135 allocs vs 8865 for Greedy in the large benchmark).
  • maxIndex accepting seq iter.Seq[WidthCount]: The caller's hiter.Map stays lazy, avoiding a []WidthCount materialization.

Where iter/lo hurts (improve in future)

  • transposedRows construction (greedy.go:48-57): hiter.Map + hiter.Concat + hiter.Once + slices.Collect chain causes columns x rows closure calls and slice allocations. Additionally, lo.Must(lo.Nth(in, columnIdx)) performs O(n) linear scan per cell instead of direct index access. This is the primary cause of Greedy's high allocation count.
  • lo.Sum(adjustedWidths) in formatIntermediate: Called on every greedy loop iteration. Even when slog.Debug is disabled, the closure arguments are evaluated.
  • adjustToSum (width.go:103-122): Loop body creates new slices each iteration via lo.Uniq, slices.SortedFunc, hiter.Nth, slices.Collect(clipToMax(...)), and lo.Sum.

These are inherited from the original code and intentionally left unchanged in this PR to keep the extraction clean. Addressing them would reduce Greedy's allocations significantly (closer to MarginalCost's 135 allocs level).

@apstndb
Copy link
Owner Author

apstndb commented Mar 16, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a well-designed WidthStrategy interface to make column width calculation pluggable, which is a great improvement for extensibility. The implementation of the three strategies is clear and includes good test coverage and benchmarks. I've found one issue in the new ProportionalStrategy where leftover width might not be distributed, potentially leading to incorrect table formatting. My review includes a suggestion to fix this.

@apstndb
Copy link
Owner Author

apstndb commented Mar 16, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the column width calculation by introducing a WidthStrategy interface, allowing for pluggable algorithms. The existing frequency-based logic is moved into a GreedyFrequencyStrategy, and two new strategies, Proportional and MarginalCost, are added. A new system variable, CLI_WIDTH_STRATEGY, is introduced to select the algorithm at runtime. The changes are integrated into the formatting and system variable systems, and include new unit tests and benchmarks for the strategies. My review of the implementation did not identify any issues.

When all columns reach their natural width, leftover from integer
division rounding was not distributed. Fall back to the first column
to ensure the table always uses the full available width.

Also add a NOTE comment to GreedyFrequencyStrategy documenting the
same limitation inherited from the original calculateOptimalWidth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apstndb
Copy link
Owner Author

apstndb commented Mar 17, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a well-executed refactoring that introduces a WidthStrategy interface to make the column width calculation algorithm pluggable. The existing logic is cleanly extracted into a GreedyFrequencyStrategy, and two new strategies (Proportional and MarginalCost) are added, providing more options for table formatting. The changes are well-tested with unit tests, comparison tests, and benchmarks.

I found one critical issue: a potential panic in the MarginalCostStrategy when handling a result with zero columns. I've left a comment with a suggested fix. Overall, this is a high-quality contribution that significantly improves the flexibility and design of the table formatting logic.

apstndb and others added 2 commits March 18, 2026 00:27
Pass verboseHeaders as the headers parameter to strategies instead of
prepending them to rows. Strategies already include headers once in
their data, so this ensures headers are counted exactly once.

Update test expectation for verbose mode where the initial proportional
allocation now correctly reflects verbose header display widths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Strategies already include headers in their data, so passing headers
as part of rows was double-counting them in benchmark measurements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apstndb
Copy link
Owner Author

apstndb commented Mar 17, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a well-executed refactoring that introduces a WidthStrategy interface for pluggable column width algorithms. It successfully extracts the existing logic into a default strategy, adds two new advanced strategies, and fixes a header double-counting bug. The changes are well-structured and come with comprehensive tests and benchmarks. Upon further review, the previously identified potential panic in MarginalCostStrategy for zero columns is considered an over-engineered defensive check, as such scenarios are guaranteed not to occur in practice based on existing data source guarantees.

@apstndb
Copy link
Owner Author

apstndb commented Mar 17, 2026

/gemini summary

@gemini-code-assist
Copy link
Contributor

Summary of Changes

This pull request refactors the table formatting subsystem to introduce a flexible and extensible architecture for column width allocation. By abstracting the width calculation logic behind an interface, it enables runtime selection of different algorithms, improving control over table rendering and setting the stage for future enhancements like non-wrapping columns.

Highlights

  • Pluggable Column Width Algorithms: Introduced a WidthStrategy interface to allow runtime selection of column width algorithms, addressing a prerequisite for Introduce NoWrapCell to generalize minColumnWidth hardcoding #567 (NoWrapCell).
  • New Width Strategies Implemented: Implemented three distinct strategies: GREEDY_FREQUENCY (the existing default behavior), PROPORTIONAL (deficit-proportional allocation), and MARGINAL_COST (wrap-line minimization using a max-heap).
  • System Variable Integration: Added CLI_WIDTH_STRATEGY as a new system variable, enabling users to configure the desired width allocation algorithm via the CLI.
  • Refactored Width Calculation Logic: The monolithic calculateOptimalWidth() function was refactored to delegate to the new WidthStrategy interface, improving modularity and extensibility.
  • Bug Fix: Header Double-Counting: Resolved an issue where headers were counted twice in width calculations, ensuring they are now included exactly once by strategies.
Changelog
  • enums/enums.go
    • Added WidthStrategy enum type with GreedyFrequency, Proportional, and MarginalCost values.
    • Included go:generate directive for enum code generation.
  • enums/widthstrategy_enumer.go
    • Generated Go code for the WidthStrategy enum, including String(), WidthStrategyString(), and WidthStrategyValues() methods.
  • internal/mycli/cli_test.go
    • Updated the expected output for a test case to reflect changes in column width calculation.
  • internal/mycli/format/config.go
    • Imported the new enums package.
    • Added WidthStrategy field to FormatConfig struct to store the selected column width algorithm.
  • internal/mycli/format/streaming_table.go
    • Modified calculateWidths to call CalculateWidthWithStrategy, passing the configured WidthStrategy.
  • internal/mycli/format/width.go
    • Removed fmt import as it is no longer directly used in the refactored logic.
    • Updated CalculateWidth to call CalculateWidthWithStrategy with WidthStrategyGreedyFrequency as the default.
    • Replaced the original calculateOptimalWidth function with CalculateWidthWithStrategy, which now computes overhead, creates hints, and delegates to the appropriate WidthStrategy implementation.
    • Added wrapLinesForWidth and splitLines helper functions for calculating text wrapping.
  • internal/mycli/format/width_strategy.go
    • Added ColumnHint struct for per-column metadata, including a NoWrap field reserved for future use.
    • Defined the WidthStrategy interface with a CalculateWidths method.
    • Implemented NewWidthStrategy factory function to return the correct strategy based on the WidthStrategy enum value.
  • internal/mycli/format/width_strategy_bench_test.go
    • Added new benchmark tests for WidthStrategy implementations, covering small, medium, and large datasets.
  • internal/mycli/format/width_strategy_greedy.go
    • Implemented GreedyFrequencyStrategy which encapsulates the original frequency-based greedy expansion algorithm for column width calculation.
  • internal/mycli/format/width_strategy_marginal.go
    • Implemented MarginalCostStrategy to minimize total wrap-lines using a greedy max-heap approach, with helper functions for calculating wrap lines and managing the heap.
  • internal/mycli/format/width_strategy_proportional.go
    • Implemented ProportionalStrategy to allocate column widths proportionally to their natural width, distributing remaining space based on deficit.
  • internal/mycli/format/width_strategy_test.go
    • Added unit tests for GreedyFrequencyStrategy, ProportionalStrategy, MarginalCostStrategy, and NewWidthStrategy.
    • Included TestCompareStrategies to log and compare outputs of different strategies, and TestStrategyMinColumnWidth to ensure minimum width adherence.
  • internal/mycli/system_variables.go
    • Added WidthStrategy field to DisplayVars struct.
    • Mapped the Display.WidthStrategy to format.FormatConfig.WidthStrategy in the toFormatConfig() method.
  • internal/mycli/system_variables_test.go
    • Imported enums package for WidthStrategy enum.
    • Added a new test suite for WidthStrategy enum types, verifying valid and invalid value parsing and case insensitivity.
    • Included CLI_WIDTH_STRATEGY in TestSystemVariables_SetGetOperations string tests.
  • internal/mycli/var_enum_handlers.go
    • Added WidthStrategyVar helper function to create an enum handler for the WidthStrategy type.
  • internal/mycli/var_registry.go
    • Registered the new CLI_WIDTH_STRATEGY system variable with its description and associated enum handler.
Activity
  • The author provided benchmark results on an Apple M2, showing performance characteristics for small, medium, and large datasets across all three width strategies.
  • A comparison of strategies was logged, demonstrating how each algorithm produces different width allocations and total wrap counts.
  • A comprehensive test plan was outlined and executed, including make check, existing regression tests, new strategy-specific tests, and system variable tests for CLI_WIDTH_STRATEGY.
  • The author added performance improvement notes for future work, detailing where iter helps and hurts in the current implementation.
  • A gemini-code-assist[bot] review highlighted that splitLines and wrapLinesForWidth were misplaced and suggested refactoring splitLines to use strings.IndexByte. The author addressed this in commit fc8fb51.
  • A gemini-code-assist[bot] review identified a flaw in the ProportionalStrategy's leftover width distribution, where MaxWithIdx could return -1, causing the total width to be less than available. A fix was suggested to fall back to the first column. The author addressed this in commit 2cd0484.
  • A gemini-code-assist[bot] review identified a critical panic risk in MarginalCostStrategy if numCols was zero, due to accessing currentWrapLines[0]. A guard was suggested to prevent this.

…olumns

Add numCols > 0 check to prevent potential panic on currentWrapLines[0]
when headers is empty.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apstndb
Copy link
Owner Author

apstndb commented Mar 17, 2026

/gemini review

@apstndb apstndb merged commit 41f4265 into main Mar 17, 2026
2 checks passed
@apstndb apstndb deleted the issue-566-width-strategy-interface branch March 17, 2026 15:57
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a great refactoring of the column width calculation logic. Introducing the WidthStrategy interface makes the system more modular and extensible, and the addition of new strategies like PROPORTIONAL and MARGINAL_COST provides valuable new formatting options. The bug fix for header double-counting is also a welcome improvement. I've found a couple of issues in the new strategy implementations that should be addressed.

Comment on lines +52 to +54
func(in Row) string {
return lo.Must(lo.Nth(in, columnIdx)).RawText()
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There's a potential panic here. The hiter.Map function iterates over all rows, including those from the rows slice. If any of these rows are shorter than len(headers), lo.Nth(in, columnIdx) will return an error for an out-of-bounds columnIdx, and lo.Must will cause a panic. The other new strategies (ProportionalStrategy and MarginalCostStrategy) correctly handle this by checking if the column index is within the row's bounds. A similar check should be added here for safety.

func(in Row) string {
	if columnIdx < len(in) {
		return in[columnIdx].RawText()
	}
	return ""
},

Comment on lines +67 to +95
if remaining > 0 && totalDeficit > 0 {
distributed := 0
for i := range numCols {
if deficits[i] > 0 {
share := remaining * deficits[i] / totalDeficit
// Don't exceed the natural width.
share = min(share, deficits[i])
adjustedWidths[i] += share
distributed += share
}
}

// Assign leftover (from integer division rounding) to the column with
// the largest remaining deficit. If all columns have reached their
// natural width, fall back to the first column to ensure the full
// available width is always used.
leftover := remaining - distributed
if leftover > 0 && numCols > 0 {
remainingDeficits := make([]int, numCols)
for i := range numCols {
remainingDeficits[i] = naturalWidths[i] - adjustedWidths[i]
}
idx, _ := MaxWithIdx(0, slices.Values(remainingDeficits))
if idx < 0 {
idx = 0
}
adjustedWidths[idx] += leftover
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation of ProportionalStrategy does not distribute any remaining width if totalDeficit is 0. This can happen if the initial header-based allocation is already sufficient for the natural width of all columns. As a result, the table may not use the full available screen width. The MarginalCostStrategy and the fallback logic for distributing leftover width suggest the intent is to always utilize the available space. The logic should be adjusted to handle this case, for example by distributing the remaining width to the column with the largest natural width.

if remaining > 0 {
		distributed := 0
		if totalDeficit > 0 {
			for i := range numCols {
				if deficits[i] > 0 {
					share := remaining * deficits[i] / totalDeficit
					// Don't exceed the natural width.
					share = min(share, deficits[i])
					adjustedWidths[i] += share
					distributed += share
				}
			}
		}

		// Assign leftover (from integer division rounding or if totalDeficit was 0)
		// to the column with the largest remaining deficit. If all columns have
		// reached their natural width, fall back to the first column to ensure
		// the full available width is always used.
		leftover := remaining - distributed
		if leftover > 0 && numCols > 0 {
			remainingDeficits := make([]int, numCols)
			for i := range numCols {
				remainingDeficits[i] = naturalWidths[i] - adjustedWidths[i]
			}
			idx, _ := MaxWithIdx(0, slices.Values(remainingDeficits))
			if idx < 0 {
				idx = 0
			}
			adjustedWidths[idx] += leftover
		}
	}

apstndb added a commit that referenced this pull request Mar 17, 2026
Fix unresolved review issues from #569: GreedyFrequencyStrategy panic on
short rows, ProportionalStrategy not distributing remaining width when
totalDeficit is zero, and GreedyFrequencyStrategy not using full width when
all columns fit. Also reduce allocations in transposedRows construction and
adjustToSum by replacing iterator chains with direct loops.

Fixes #570, fixes #571

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
apstndb added a commit that referenced this pull request Mar 18, 2026
Fix unresolved review issues from #569 and reduce allocations in GreedyFrequencyStrategy.

Bug fixes:
- Add empty headers guard in GreedyFrequencyStrategy to prevent panic
- Replace lo.Must(lo.Nth()) with direct index access + bounds check to prevent panic on short rows
- Always distribute remainder width (fall back to column 0) in GreedyFrequencyStrategy
- Fix ProportionalStrategy to distribute remaining width when totalDeficit == 0

Performance:
- Replace hiter.Map/hiter.Concat/slices.Collect chain in transposedRows with direct slice construction
- Replace lo.Sum with inline sumWidths to avoid evaluation on every slog.Debug call
- Optimize adjustToSum: compute sorted unique thresholds once, inline clipping + sum
- Remove unused clipToMax function

Tests:
- Add TestGreedyFrequencyStrategy_ShortRows, TestProportionalStrategy_ZeroDeficit, TestGreedyFrequencyStrategy_FullWidth

Fixes #570, fixes #571
apstndb added a commit that referenced this pull request Mar 22, 2026
Document the new pluggable width strategy system variable added in #569.
Add CLI_WIDTH_STRATEGY entry to docs/system_variables.md with all three
algorithm options and usage notes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apstndb apstndb mentioned this pull request Mar 22, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce WidthStrategy interface for pluggable column width algorithms

1 participant