Skip to content

[CLI] Auto-fit human tables to terminal width#4251

Merged
hanouticelina merged 9 commits into
mainfrom
cli-adaptive-table-width
May 27, 2026
Merged

[CLI] Auto-fit human tables to terminal width#4251
hanouticelina merged 9 commits into
mainfrom
cli-adaptive-table-width

Conversation

@hanouticelina

@hanouticelina hanouticelina commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #4229.

This PR replaces the hardcoded 35-char per-cell cap in human tables with a column-aware algorithm that uses the actual terminal width. non-tty keeps the legacy 35 char cap, --no-truncate bypasses the adaptive logic entirely. with a narrow terminal, only the widest columns shrink, naturally narrow columns (dates, ints, headers) keep their natural width. for very narrow, columns shrink to a per-column floor (max(10, header_len)), table wraps slightly.

# Defaults - using your actual terminal width
$ echo $COLUMNS
191
$ hf models ls --search qwen3
ID                                                                        CREATED_AT DOWNLOADS LIBRARY_NAME LIKES PIPELINE_TAG       PRIVATE TAGS                                TRENDING_SCORE
------------------------------------------------------------------------- ---------- --------- ------------ ----- ------------------ ------- ----------------------------------- --------------
unsloth/Qwen3.6-27B-MTP-GGUF                                              2026-05-11 532255    transformers 386   image-text-to-text         transformers, gguf, unsloth, qwe... 224
unsloth/Qwen3.6-35B-A3B-MTP-GGUF                                          2026-05-11 466060    transformers 320   image-text-to-text         transformers, gguf, unsloth, qwe... 180
Qwen/Qwen3.6-27B                                                          2026-04-21 4049995   transformers 1379  image-text-to-text         transformers, safetensors, qwen3... 83
Qwen/Qwen3.6-35B-A3B                                                      2026-04-15 5978432   transformers 1854  image-text-to-text         transformers, safetensors, qwen3... 73
HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive                   2026-04-17 1218357                692   image-text-to-text         gguf, uncensored, qwen3.6, moe, ... 51
DavidAU/Qwen3.6-27B-Heretic-Uncensored-FINETUNE-NEO-CODE-Di-IMatrix-MA... 2026-04-29 443744                 208   image-text-to-text         gguf, unsloth, heretic, uncensor... 49
DavidAU/Qwen3.6-40B-Claude-4.6-Opus-Deckard-Heretic-Uncensored-Thinkin... 2026-05-01 343683    transformers 132   image-text-to-text         transformers, gguf, unsloth, fin... 45
unsloth/Qwen3.6-35B-A3B-GGUF                                              2026-04-16 2425597   transformers 1085  image-text-to-text         transformers, gguf, unsloth, qwe... 43
unsloth/Qwen3.5-9B-MTP-GGUF                                               2026-05-13 82298     transformers 51    image-text-to-text         transformers, gguf, unsloth, qwe... 39
llmfan46/Qwen3.6-27B-uncensored-heretic-v2-Native-MTP-Preserved-GGUF      2026-05-06 63779     transformers 70    image-text-to-text         transformers, gguf, qwen3_5, her... 35


# Wide terminal - full IDs visible.
$ COLUMNS=250 hf models ls --search qwen3
ID                                                                                                   CREATED_AT DOWNLOADS LIBRARY_NAME LIKES PIPELINE_TAG       PRIVATE TAGS                                TRENDING_SCORE
---------------------------------------------------------------------------------------------------- ---------- --------- ------------ ----- ------------------ ------- ----------------------------------- --------------
unsloth/Qwen3.6-27B-MTP-GGUF                                                                         2026-05-11 532255    transformers 386   image-text-to-text         transformers, gguf, unsloth, qwe... 224
unsloth/Qwen3.6-35B-A3B-MTP-GGUF                                                                     2026-05-11 466060    transformers 320   image-text-to-text         transformers, gguf, unsloth, qwe... 180
Qwen/Qwen3.6-27B                                                                                     2026-04-21 4049995   transformers 1379  image-text-to-text         transformers, safetensors, qwen3... 83
Qwen/Qwen3.6-35B-A3B                                                                                 2026-04-15 5978432   transformers 1854  image-text-to-text         transformers, safetensors, qwen3... 73
HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive                                              2026-04-17 1218357                692   image-text-to-text         gguf, uncensored, qwen3.6, moe, ... 51
DavidAU/Qwen3.6-27B-Heretic-Uncensored-FINETUNE-NEO-CODE-Di-IMatrix-MAX-GGUF                         2026-04-29 443744                 207   image-text-to-text         gguf, unsloth, heretic, uncensor... 48
DavidAU/Qwen3.6-40B-Claude-4.6-Opus-Deckard-Heretic-Uncensored-Thinking-NEO-CODE-Di-IMatrix-MAX-GGUF 2026-05-01 343683    transformers 132   image-text-to-text         transformers, gguf, unsloth, fin... 45
unsloth/Qwen3.6-35B-A3B-GGUF                                                                         2026-04-16 2425597   transformers 1085  image-text-to-text         transformers, gguf, unsloth, qwe... 43
unsloth/Qwen3.5-9B-MTP-GGUF                                                                          2026-05-13 82298     transformers 51    image-text-to-text         transformers, gguf, unsloth, qwe... 39
llmfan46/Qwen3.6-27B-uncensored-heretic-v2-Native-MTP-Preserved-GGUF                                 2026-05-06 63779     transformers 70    image-text-to-text         transformers, gguf, qwen3_5, her... 35

# Midnarrow - adaptive shrink. 
$ COLUMNS=140 hf models ls --search qwen3
ID                           CREATED_AT DOWNLOADS LIBRARY_NAME LIKES PIPELINE_TAG       PRIVATE TAGS                          TRENDING_SCORE
---------------------------- ---------- --------- ------------ ----- ------------------ ------- ----------------------------- --------------
unsloth/Qwen3.6-27B-MTP-GGUF 2026-05-11 532255    transformers 386   image-text-to-text         transformers, gguf, unslot... 224
unsloth/Qwen3.6-35B-A3B-M... 2026-05-11 466060    transformers 320   image-text-to-text         transformers, gguf, unslot... 180
Qwen/Qwen3.6-27B             2026-04-21 4049995   transformers 1379  image-text-to-text         transformers, safetensors,... 83
Qwen/Qwen3.6-35B-A3B         2026-04-15 5978432   transformers 1854  image-text-to-text         transformers, safetensors,... 73
HauhauCS/Qwen3.6-35B-A3B-... 2026-04-17 1218357                692   image-text-to-text         gguf, uncensored, qwen3.6,... 51
DavidAU/Qwen3.6-27B-Heret... 2026-04-29 443744                 207   image-text-to-text         gguf, unsloth, heretic, un... 48
DavidAU/Qwen3.6-40B-Claud... 2026-05-01 343683    transformers 132   image-text-to-text         transformers, gguf, unslot... 45
unsloth/Qwen3.6-35B-A3B-GGUF 2026-04-16 2425597   transformers 1085  image-text-to-text         transformers, gguf, unslot... 43
unsloth/Qwen3.5-9B-MTP-GGUF  2026-05-13 82298     transformers 51    image-text-to-text         transformers, gguf, unslot... 39
llmfan46/Qwen3.6-27B-unce... 2026-05-06 63779     transformers 70    image-text-to-text         transformers, gguf, qwen3_... 35


# Very narrow - shrink to floor.
$ COLUMNS=80 hf models ls --search qwen3
ID         CREATED_AT DOWNLOADS LIBRARY_NAME LIKES PIPELINE_TAG PRIVATE TAGS       TRENDING_SCORE
---------- ---------- --------- ------------ ----- ------------ ------- ---------- --------------
unsloth... 2026-05-11 532255    transformers 386   image-tex...         transfo... 224
unsloth... 2026-05-11 466060    transformers 320   image-tex...         transfo... 180
Qwen/Qw... 2026-04-21 4049995   transformers 1379  image-tex...         transfo... 83
Qwen/Qw... 2026-04-15 5978432   transformers 1854  image-tex...         transfo... 73
HauhauC... 2026-04-17 1218357                692   image-tex...         gguf, u... 51
DavidAU... 2026-04-29 443744                 207   image-tex...         gguf, u... 48
DavidAU... 2026-05-01 343683    transformers 132   image-tex...         transfo... 45
unsloth... 2026-04-16 2425597   transformers 1085  image-tex...         transfo... 43
unsloth... 2026-05-13 82298     transformers 51    image-tex...         transfo... 39
llmfan4... 2026-05-06 63779     transformers 70    image-tex...         transfo... 35

Note

Medium Risk
Changes core CLI table rendering logic, which could subtly affect output formatting and truncation behavior across many commands (especially in narrow terminals or when piping output). Functionality is localized to display concerns with test coverage added for the new adaptive behavior.

Overview
Human-mode CLI tables now auto-fit the terminal width instead of truncating every cell at a fixed 35 characters.

This adds a column-aware truncation algorithm that computes per-column width caps from the detected terminal width, shrinks only the widest columns when needed, keeps the legacy fixed cap for non-TTY output, and leaves --no-truncate as an override to bypass truncation. Documentation and tests were updated to describe and validate the adaptive shrinking behavior.

Reviewed by Cursor Bugbot for commit ed2b809. Configure here.

@bot-ci-comment

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@hanouticelina hanouticelina left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ok looks good to me ✔️ ready for review

@hanouticelina hanouticelina marked this pull request as ready for review May 22, 2026 12:24
@hanouticelina hanouticelina requested a review from Wauplin May 22, 2026 12:25

@Wauplin Wauplin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sorry more comments that I would have thought because it took me some time to understand the different subtleties. The main feedback is that I think now we do adaptative truncation we should be less opinionated (i.e less hardcoded stuff) than before

Comment thread tests/test_cli_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment on lines +315 to +316
if no_truncate:
return natural.copy()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ok I see, the "let's truncate container values to arbitrary 35 cols" is useful when using --no-truncate so that we still truncate columns that might be extremely long (like a json dump^^). What do you think of instead of --no-truncate we allow users to do a --truncate 1000 for instance? (in which case we consider the terminal to be 1000 columns width). This way the user can set the value they want and we don't take decisions for them

and maybe still allow --no-truncate for "don't truncate at all, even if extremely long line" (or accept --truncate -1 but feels weird? 😕)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

in any case, I would move all the truncation logic inside _compute_column_caps (could be renamed _truncate_columns?). At the moment values are truncated before and inside the method

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

in any case, I would move all the truncation logic inside _compute_column_caps (could be renamed _truncate_columns?). At the moment values are truncated before and inside the method

_truncate_columns now does width calc, shrinking and truncation.

Ok I see, the "let's truncate container values to arbitrary 35 cols" is useful when using --no-truncate so that we still truncate columns that might be extremely long (like a json dump^^). What do you think of instead of --no-truncate we allow users to do a --truncate 1000 for instance? (in which case we consider the terminal to be 1000 columns width). This way the user can set the value they want and we don't take decisions for them

yes why not, I'm okay with breaking --no-truncate. added this in my TODO (low prio imo), I will open a follow-up PR and discuss the flags semantics there if that's okay with you

Comment thread tests/test_cli_output.py Outdated
@Wauplin Wauplin self-requested a review May 22, 2026 15:30

@Wauplin Wauplin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Made another pass especially on the --no-truncate part

Comment thread docs/source/en/guides/cli.md Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment thread src/huggingface_hub/cli/_output.py Outdated
Comment on lines 136 to 139

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if is_truncated:
self.hint("Use `--no-truncate` or `--format json` to display full values.")

and then update the hints here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

updated in d261f4e

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pinact found unpinned actions in this repo.

Auto-fixable, but outside this PR's diff (run pinact run locally and commit):

  • .github/workflows/model_card_consistency_reminder.yml:15actions/checkout@v6actions/checkout@de0fac2e45… # v6.0.2
  • .github/workflows/python-prerelease.yml:34actions/checkout@v6actions/checkout@de0fac2e45… # v6.0.2
  • .github/workflows/python-quality.yml:23- actions/checkout@v6- actions/checkout@de0fac2e45… # v6.0.2
  • .github/workflows/python-quality.yml:25actions/setup-python@v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/python-tests.yml:22actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/python-tests.yml:57actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/python-tests.yml:152codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5codecov/codecov-action@75cd11691c… # v5.5.4
  • .github/workflows/python-tests.yml:174actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/python-tests.yml:221codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5codecov/codecov-action@75cd11691c… # v5.5.4
  • .github/workflows/release.yml:293- actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6- actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/release.yml:348- actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6- actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/release.yml:435- actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6- actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/release.yml:555- actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6- actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/release.yml:690- actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6- actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/release.yml:930actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2actions/create-github-app-token@fee1f7d63c… # v2.2.2
  • .github/workflows/release.yml:1018actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/release.yml:1032actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2actions/create-github-app-token@fee1f7d63c… # v2.2.2
  • .github/workflows/release.yml:1056peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7peter-evans/create-pull-request@22a9089034… # v7.0.11
  • .github/workflows/release.yml:1109actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2actions/create-github-app-token@fee1f7d63c… # v2.2.2
  • .github/workflows/style-bot-action.yml:47actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/style-bot-action.yml:77actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/style-bot-action.yml:122actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/style-bot-action.yml:140actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/style-bot-action.yml:184actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/style-bot-action.yml:260actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/style-bot-action.yml:303actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/style-bot-action.yml:369actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8actions/github-script@ed597411d8… # v8.0.0
  • .github/workflows/sync-hf-cli-skill.yml:17actions/checkout@v4actions/checkout@34e114876b… # v4.3.1
  • .github/workflows/sync-hf-cli-skill.yml:20actions/setup-python@v5actions/setup-python@a26af69be9… # v5.6.0
  • .github/workflows/sync-hf-cli-skill.yml:46actions/create-github-app-token@v2actions/create-github-app-token@fee1f7d63c… # v2.2.2
  • .github/workflows/sync-hf-cli-skill.yml:53actions/checkout@v4actions/checkout@34e114876b… # v4.3.1
  • .github/workflows/sync-hf-cli-skill.yml:60astral-sh/setup-uv@v7astral-sh/setup-uv@37802adc94… # v7.6.0
  • .github/workflows/sync-hf-cli-skill.yml:86peter-evans/create-pull-request@v7peter-evans/create-pull-request@22a9089034… # v7.0.11
  • .github/workflows/build_repocard_examples.yaml:18actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/update-inference-types.yaml:22actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6actions/setup-python@a309ff8b42… # v6.2.0
  • .github/workflows/update-inference-types.yaml:37- actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6- actions/setup-node@53b83947a5… # v6.3.0
  • .github/workflows/update-inference-types.yaml:41pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4pnpm/action-setup@b906affcce… # v4.3.0
  • .github/workflows/update-inference-types.yaml:71peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8peter-evans/create-pull-request@c0f553fe54… # v8.1.0

@hanouticelina hanouticelina requested a review from Wauplin May 27, 2026 12:41

@Wauplin Wauplin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks great, thanks!

@hanouticelina hanouticelina merged commit c06e976 into main May 27, 2026
26 checks passed
@hanouticelina hanouticelina deleted the cli-adaptive-table-width branch May 27, 2026 14:33
@huggingface-hub-bot

Copy link
Copy Markdown
Contributor

This PR has been shipped as part of the v1.17.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants