-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make terminal table more responsive #7391
Conversation
@@ -31,4 +31,14 @@ def truncate(truncate_at, options = {}) | |||
|
|||
"#{self[0, stop]}#{omission}" | |||
end | |||
|
|||
# Base taken from: http://stackoverflow.com/a/12202205/1945875 | |||
def middle_truncate(length = 20, options = {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a good way to detect the initial terminal width?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KrauseFx
this is just a generic function.
in the table printer itself - the terminal width is used
tcols = IO.console.winsize[1]
max_length = tcols
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, cool 👍
512b1ad
to
43de68a
Compare
This is a really good idea, however, I would also like an option to disable this (e.g. when running on CI) so that users have at least an option to see the whole thing for debugging purposes. |
053150d
to
dfb45b1
Compare
@milch ok done - truncate = false if Helper.is_ci? || FastlaneCore::Env.truthy?("DO_NOT_TRUNCATE_TABLES") sorry for the force push, as i had to rebase for the |
No worries, I haven't reviewed yet 👍
This is a bit nitpicky but mostly we'd like to prefix ENV-vars. Can we call it |
@@ -18,7 +18,10 @@ def print_values(config: nil, title: nil, hide_keys: [], mask_keys: []) | |||
rows = self.collect_rows(options: options, hide_keys: hide_keys.map(&:to_s), mask_keys: mask_keys.map(&:to_s), prefix: '') | |||
|
|||
params = {} | |||
params[:rows] = limit_row_size(rows) | |||
truncate = false if Helper.is_ci? || FastlaneCore::Env.truthy?("DO_NOT_TRUNCATE_TABLES") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of DO_NOT
, we've used SKIP_...
until now
This looks super promising, ideally it would also be used for the action table: #7811 |
@KrauseFx feedback addressed. |
@KrauseFx ok i updated it to also work with newlines instead of the here is a sample to test: require "fastlane_core"
FastlaneCore::PrintTable.print_values(config:
{ wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
wwwwwwwwwwwwwwwwwwwwwwwwxw: "ccc bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" },
hide_keys: [],
title: "Summary SUM")
FastlaneCore::PrintTable.print_values(config:
{ wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
wwwwwwwwwwwwwwwwwwwwwwwwxw: "ccc bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" },
hide_keys: [],
title: "Summary SUM",
transform: :newline) and i also added support for this in the
and in detailed action descr.:
|
is there a way to make the line wraps happen at word boundaries? from the screenshot above there are several words that are broken up from one line to the next |
@jinjorge good point, but i think there are cases where really long words would not be wrapped and resulting in a ugly table, you have a idea on how to solve that? |
@hjanuschka It's a numbers game - there are a lot more sub 5-6 letter words than really long words. Probably best to optimize for the majority and see how things fall out. To you question on how to solve it - I don't know, though I will do some research. |
b74e04e
to
e3fdf48
Compare
test's pass now, ready for new review! @jinjorge i am unsure on how to solve it without breaking the output. |
a regular expression match ( |
@jinjorge got it working !!! respecting whole word, but if too long forcing to break it! ;) # Base taken from: https://www.ruby-forum.com/topic/57805
def wordwrap(length = 80)
self.gsub!(/(\S{#{length}})(?=\S)/, '\1 ')
self.scan(/.{1,#{length}}(?:\s+|$)/)
end |
👏 👏 Awesome!!! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me aside from a couple minor things. I really think we should merge this soon
return_array = [] | ||
tcols = IO.console.winsize[1] | ||
|
||
col_count = rows.map(&:length).first || 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is 1 being used as default here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i used to use 0 - but well we have always atleast one column, otherwise it crashes later on due to a division by zero 💃
value = col.to_s.dup | ||
if transform == :truncate_middle | ||
value = value.middle_truncate(max_value_length) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use elsif
here to more clearly show intent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, going to adress this once back in private life 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhh sorry to fast reply, i think there are cases where transform is false
(e.g: CI run)
so its neither :newline nor :truncate_middle - any other ideas?
@milch feedback addressed, as we have the super awesome full-word split now i enabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like where this is going 👍
@@ -24,7 +24,14 @@ def print_values(config: nil, title: nil, hide_keys: [], mask_keys: []) | |||
rows = self.collect_rows(options: options, hide_keys: hide_keys.map(&:to_s), mask_keys: mask_keys.map(&:to_s), prefix: '') | |||
|
|||
params = {} | |||
params[:rows] = limit_row_size(rows) | |||
transform = false if FastlaneCore::Env.truthy?("SKIP_TRANSFORM_TABLES") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FL_SKIP_TABLE_TRANSFORM
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
max_key_length = rows.map { |e| e[0].length }.max || 0 | ||
max_allowed_value_length = max_length - max_key_length - 7 | ||
rows.map do |e| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rows.map do |row|
? - single letter variable made it pretty difficult to infer when scan reading
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true point, fixed
terminal_table_padding = 4 | ||
max_length = tcols - (col_count * terminal_table_padding) | ||
|
||
max_value_length = (max_length / col_count) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need parens here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we keep them?, i like it a bit more from point of readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to only prefer them when there are multiple expressions to make precedence easier to read, but sure.
new_row = [] | ||
e.each do |col| | ||
value = col.to_s.dup | ||
if transform == :truncate_middle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice to break this out into a transform_row/column function, because then appending to the row will be in a single place and be easier to maintain and test
i.e
def transform_row(transform, row)
row.map do |column|
transform_column(transform, column)
end
end
def transform_column(transform, column)
if transform == :truncate_middle
...
value
elseif transform == :newline
...
value
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i am not 100% comfortable with this, as there is bunch a logic going on in :newline, colorization for example - lets keep it as it is, and try to finish this PR - as its a really long running one, and do the modularization in a seperate PR. (i just broke way too much with last minute quick-changes :sad:, last PRs)
3314050
to
c4ebdfb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feedback adressed, master rebased and tty-screen used 👍
@@ -24,7 +24,14 @@ def print_values(config: nil, title: nil, hide_keys: [], mask_keys: []) | |||
rows = self.collect_rows(options: options, hide_keys: hide_keys.map(&:to_s), mask_keys: mask_keys.map(&:to_s), prefix: '') | |||
|
|||
params = {} | |||
params[:rows] = limit_row_size(rows) | |||
transform = false if FastlaneCore::Env.truthy?("FL_SKIP_TABLE_TRANSFORM") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than overloading this, I'd maybe extract out a transform?
method that is !FastlaneCore::Env.truthy?...
and have the if statement be if transform? ...
- this means you don't need to trace through mutating state.
|
||
rows.map do |row| | ||
new_row = [] | ||
row.each do |col| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as we only return one value from this, we could do new_row = row.map do |col|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might also be easier to read if we break the contents of this block into a transform_column(column, truncation_style)
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated 👍
@@ -34,16 +41,60 @@ def print_values(config: nil, title: nil, hide_keys: [], mask_keys: []) | |||
return params | |||
end | |||
|
|||
def limit_row_size(rows, max_length = 100) | |||
def colorize_array(array, colors) | |||
value = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can write this logic more clearly.
array.map { |l| "#{colors.first[0]}#{l}#{colors.last[0]}" unless colors.empty? }.join('\n')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this may not be equivalent, because it can create nil
entries
Just checking in on the status of this PR - can the feedback be addressed? Everyone seems pretty positive about getting it in! 👍 |
Improving all fastlane tables is definitely something we should fix, it's a big issue currently. @hjanuschka, is that something you want to finish up? 🚀 |
@KrauseFx yeah i want to see this in. so, how about merging this, and later on the feedback suggesters go on with it? |
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. |
@googlebot thx for this, i accidentally commited with corporate email - as soon as we know how to proceed with this PR i am going to rebase then it should be fine 👍 |
c4ebdfb
to
1b0b09b
Compare
CLAs look good, thanks! |
master rebased, cla stuff sorted out. |
@@ -34,16 +41,60 @@ def print_values(config: nil, title: nil, hide_keys: [], mask_keys: []) | |||
return params | |||
end | |||
|
|||
def limit_row_size(rows, max_length = 100) | |||
def colorize_array(array, colors) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is never called, should it be part of this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whops, never mind, it is used
new_row << value | ||
end | ||
return_array << new_row | ||
return_array << :separator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have this here? This will result in a new line of dashes inbetween every row, making the table a lot bigger
@@ -48,15 +48,15 @@ | |||
|
|||
value = FastlaneCore::PrintTable.print_values(config: @config, title: title, hide_keys: [:a_sensitive]) | |||
expect(value[:title]).to eq(title.green) | |||
expect(value[:rows]).to eq([['cert_name', "asdf"], ['output', '..'], ["a_bool", true]]) | |||
expect(value[:rows]).to eq([["cert_name", "asdf"], :separator, ["output", ".."], :separator, ["a_bool", "true"]]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's clearly visible that the separator
changes the existing behavior
Moved to #8809
Moved to #8809 (by mistake), I addressed all of your feedback, thanks. Also some more tests and code style changes. |
this trys to fix the ugliness of terminal table on small terminals - by making tables fit to terminal width.
in addition to the variable size, i also did a middle_truncate.
so instead of
very long va...
nowvery ... value
is displayed.Large
Medium
Small
to quickly test it use this ruby script: