Cap hook output at terminal width to prevent wrapping

Previously, _compute_cols() would calculate the ideal column width based
on hook names and message lengths, with a minimum of 80 columns. However,
it didn't consider the actual terminal width, causing the "Passed/Failed"
status to wrap to the next line on narrower terminals.

This change:
- Adds terminal width detection using shutil.get_terminal_size()
- Caps the column width at the terminal width to prevent wrapping
- Maintains the minimum of 80 columns when terminal is wide enough
- Falls back to 80 columns if terminal size cannot be determined

The algorithm now ensures output always fits within the terminal width,
similar to how pytest handles its output formatting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Kamil Monicz <kamil@monicz.dev>
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude 2025-10-28 13:02:43 +00:00
parent 65175f3cf3
commit c064dd83df
No known key found for this signature in database
2 changed files with 39 additions and 6 deletions

View file

@ -6,6 +6,7 @@ import functools
import logging
import os
import re
import shutil
import subprocess
import time
import unicodedata
@ -247,7 +248,15 @@ def _compute_cols(hooks: Sequence[Hook]) -> int:
name_len = 0
cols = name_len + 3 + len(NO_FILES) + 1 + len(SKIPPED)
return max(cols, 80)
cols = max(cols, 80)
# Cap at terminal width to prevent wrapping
try:
term_width = shutil.get_terminal_size().columns
except OSError:
term_width = 80
return min(cols, term_width)
def _all_filenames(args: argparse.Namespace) -> Iterable[str]:

View file

@ -574,21 +574,45 @@ def test_rebase(cap_out, store, repo_with_passing_hook):
@pytest.mark.parametrize(
('hooks', 'expected'),
('term_width', 'hooks', 'expected'),
(
([], 80),
([auto_namedtuple(id='a', name='a' * 51)], 81),
# Default 80-column terminal
(80, [], 80),
(80, [auto_namedtuple(id='a', name='a' * 51)], 80),
(
80,
[
auto_namedtuple(id='a', name='a' * 51),
auto_namedtuple(id='b', name='b' * 52),
],
80,
),
# Wide terminal - ideal width is used
(120, [], 80),
(120, [auto_namedtuple(id='a', name='a' * 51)], 81),
(
120,
[
auto_namedtuple(id='a', name='a' * 51),
auto_namedtuple(id='b', name='b' * 52),
],
82,
),
# Narrow terminal - capped at terminal width
(70, [], 70),
(70, [auto_namedtuple(id='a', name='a' * 10)], 70),
),
)
def test_compute_cols(hooks, expected):
assert _compute_cols(hooks) == expected
def test_compute_cols(term_width, hooks, expected):
class FakeTerminalSize:
def __init__(self):
self.columns = term_width
with mock.patch(
'shutil.get_terminal_size',
return_value=FakeTerminalSize(),
):
assert _compute_cols(hooks) == expected
@pytest.mark.parametrize(