mirror of
https://github.com/Homebrew/brew.git
synced 2026-10-28 09:34:42 +08:00
Merge pull request #24283 from Homebrew/truncate-version-strings
Truncate summary versions to fit terminal width
This commit is contained in:
3 files changed
+87
-5
No files matched your search
@@ -2,7 +2,7 @@
|
||||
|
||||
Most importantly, run `./bin/brew lgtm` (style checks, type checks and tests) to verify any file edits before prompting for input.
|
||||
|
||||
Inline any new or existing methods or variables used only once unless they are needed for unit tests.
|
||||
Inline any new or existing methods or variables used only once unless they are needed for unit tests or explain magic numbers.
|
||||
Keep the diff as small, DRY and YAGNI as possible.
|
||||
Re-read relevant files after each prompt and preserve user edits and comments.
|
||||
Before finishing, check your work and point out anything the user may not have considered.
|
||||
@@ -45,6 +45,7 @@ This is a Ruby repository with Bash scripts for faster execution that provides t
|
||||
- Use `&>/dev/null` instead of `>/dev/null 2>&1`.
|
||||
- Put a comment immediately above each `shellcheck disable` explaining why it is needed.
|
||||
- Prefer self-documenting code through strings and variable names to new explanatory comments.
|
||||
- Avoid magic numbers; use self-explanatory intermediate variables or constants to make their meaning clear.
|
||||
- Use UK spelling and punctuation; avoid em dashes and Oxford commas.
|
||||
- Wrap human-written user-facing terminal output at around 80 characters; generated output and code are exempt.
|
||||
- Update `docs/` when the behaviour it describes changes.
|
||||
|
||||
@@ -126,6 +126,69 @@ RSpec.describe Formatter do
|
||||
end
|
||||
end
|
||||
|
||||
describe ".version_changes" do
|
||||
before do
|
||||
allow($stdout).to receive(:tty?).and_return(true)
|
||||
allow(Tty).to receive(:width).and_return(40)
|
||||
end
|
||||
|
||||
test_each([
|
||||
["both versions", "1" * 40, "2" * 40, "edge #{"1" * 12}... -> #{"2" * 13}..."],
|
||||
["the old version", "1" * 40, "2.0", "edge #{"1" * 25}... -> 2.0"],
|
||||
["the new version", "1.0", "2" * 40, "edge 1.0 -> #{"2" * 25}..."],
|
||||
["a version without an old version", "2" * 40, nil, "edge #{"2" * 32}..."],
|
||||
]) do |description, old_version, new_version, expected|
|
||||
it "truncates #{description} to fit the terminal" do
|
||||
expect(described_class.version_changes([version_change("edge", old_version, new_version)]))
|
||||
.to eq([expected])
|
||||
end
|
||||
end
|
||||
|
||||
it "reserves space for download sizes and keeps columns aligned" do
|
||||
allow(Tty).to receive(:width).and_return(50)
|
||||
|
||||
expect(described_class.version_changes([
|
||||
version_change("edge", "1" * 40, "2" * 40),
|
||||
version_change("testball", "1.0", "2.0", size: "500B"),
|
||||
])).to eq([
|
||||
"edge 11111111111... -> 22222222222...",
|
||||
"testball 1.0 -> 2.0 (500B)",
|
||||
])
|
||||
end
|
||||
|
||||
test_each([
|
||||
["123.456.789,abcdef", "234.567.890,ghijkl", "edge 123.456.789... -> 234.567.890..."],
|
||||
["123.456.789", "234.567.890", "edge 123.456.789 -> 234.567.890"],
|
||||
["123.456.789,abcdef", nil, "edge 123.456.789..."],
|
||||
]) do |old_version, new_version, expected|
|
||||
it "keeps at least 11 version characters even in a very narrow terminal" do
|
||||
allow(Tty).to receive(:width).and_return(1)
|
||||
|
||||
expect(described_class.version_changes([version_change("edge", old_version, new_version)]))
|
||||
.to eq([expected])
|
||||
end
|
||||
end
|
||||
|
||||
it "preserves versions that fit the terminal exactly" do
|
||||
expect(described_class.version_changes([version_change("edge", "1" * 15, "2" * 16)]))
|
||||
.to eq(["edge #{"1" * 15} -> #{"2" * 16}"])
|
||||
end
|
||||
|
||||
it "preserves full versions when output is redirected" do
|
||||
allow($stdout).to receive(:tty?).and_return(false)
|
||||
|
||||
expect(described_class.version_changes([version_change("edge", "1" * 40, "2" * 40)]))
|
||||
.to eq(["edge #{"1" * 40} -> #{"2" * 40}"])
|
||||
end
|
||||
|
||||
it "preserves full versions when the terminal width is unknown" do
|
||||
allow(Tty).to receive(:width).and_return(0)
|
||||
|
||||
expect(described_class.version_changes([version_change("edge", "1" * 40, "2" * 40)]))
|
||||
.to eq(["edge #{"1" * 40} -> #{"2" * 40}"])
|
||||
end
|
||||
end
|
||||
|
||||
describe ".disk_usage_readable_size_unit" do
|
||||
it "returns size and unit for bytes" do
|
||||
expect(described_class.disk_usage_readable_size_unit(500)).to eq([500, "B"])
|
||||
|
||||
@@ -132,16 +132,34 @@ module Formatter
|
||||
# like `(2.4MB)` in its own column.
|
||||
sig { params(changes: T::Array[VersionChange]).returns(T::Array[String]) }
|
||||
def self.version_changes(changes)
|
||||
name_width = changes.map { |change| change.name.length }.max || 0
|
||||
separator = (changes.one? ? " " : " ")
|
||||
old_width = changes.map { |change| (change.old_version || change.new_version).length }.max || 0
|
||||
new_width = changes.filter_map { |change| change.new_version.length if change.old_version }.max || 0
|
||||
# Keep full versions in redirected output or when the terminal width is unknown.
|
||||
if $stdout.tty? && Tty.width.positive?
|
||||
# Reserve space for names, separators, size parentheses and the upgrade arrow.
|
||||
available_width = Tty.width - name_width - separator.length
|
||||
size_width = changes.filter_map { |change| change.size&.length }.max
|
||||
size_parentheses_width = 2
|
||||
available_width -= size_width + size_parentheses_width + separator.length if size_width
|
||||
upgrade_arrow_width = 4
|
||||
available_width -= upgrade_arrow_width if new_width.positive?
|
||||
|
||||
# Keep room for XXX.YYY.ZZZ plus "...", even if a very narrow terminal must wrap.
|
||||
minimum_version_width = 14
|
||||
# Share space evenly, letting a long version use space left by a short one.
|
||||
old_width = [old_width, [available_width - new_width, available_width / 2, minimum_version_width].max].min
|
||||
new_width = [available_width - old_width, minimum_version_width].max
|
||||
end
|
||||
|
||||
versions = changes.map do |change|
|
||||
old_version = change.old_version
|
||||
next change.new_version unless old_version
|
||||
next truncate(change.new_version, max: old_width) unless old_version
|
||||
|
||||
"#{old_version.ljust(old_width)} -> #{change.new_version}"
|
||||
"#{truncate(old_version, max: old_width).ljust(old_width)} -> #{truncate(change.new_version, max: new_width)}"
|
||||
end
|
||||
name_width = changes.map { |change| change.name.length }.max || 0
|
||||
versions_width = versions.map(&:length).max || 0
|
||||
separator = (changes.one? ? " " : " ")
|
||||
|
||||
changes.each_with_index.map do |change, index|
|
||||
size = "(#{change.size})" if change.size
|
||||
|
||||
Reference in new issue
Block a user