Skip to content

[Console] Make pretty the box style table #25456

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

Merged
merged 1 commit into from
Mar 17, 2018

Conversation

maidmaid
Copy link
Contributor

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets /
License MIT
Doc PR /

The console component is the 2nd most popular Symfony component with 70M of downloads. I think such composant has to provide faultless tables, with perfect management of borders, especially since the new box style table has been merged (cf #25301).

screenshot from 2017-12-12 18-47-34

Copy link
Member

@javiereguiluz javiereguiluz left a comment

Choose a reason for hiding this comment

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

Before making more changes, let's wait and see if others agree with this feature. But if they agree, we should decided if we make all separators configurable (i.e. horizontal and vertical borders).

In other libraries (e.g. https://github.com/Automattic/cli-table) they define these chars:

      chars: {
          'top': '─'
        , 'top-mid': '┬'
        , 'top-left': '┌'
        , 'top-right': '┐'
        , 'bottom': '─'
        , 'bottom-mid': '┴'
        , 'bottom-left': '└'
        , 'bottom-right': '┘'
        , 'left': '│'
        , 'left-mid': '├'
        , 'mid': '─'
        , 'mid-mid': '┼'
        , 'right': '│'
        , 'right-mid': '┤'
        , 'middle': '│'
      }

*
* @return $this
*/
public function setCrossingChars(string $cross, string $topLeft = null, string $topMiddle = null, string $topRight = null, string $middleRight = null, string $bottomRight = null, string $bottomMiddle = null, string $bottomLeft = null, string $middleLeft = null)
Copy link
Member

Choose a reason for hiding this comment

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

Instead of string $topLeft = null you can use ?string $topLeft because in master we use PHP 7.1, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not the same meaning in fact. I want to make optional these params.

function f(?string $p) {}
f(); // Uncaught Error: Too few arguments to function f(), 0 passed in...

*
* @return string $crossingTopRightChar
*/
public function getCrossingTopRightChar()
Copy link
Member

Choose a reason for hiding this comment

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

Return type-hints in these methods?

public function getCrossingTopRightChar(): string { ... }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it would be better, but the others getters of this class don't have return type-hints.

Copy link
Member

@chalasr chalasr Dec 12, 2017

Choose a reason for hiding this comment

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

not a big deal IMO, let's use new PHP features in new code
edit: I mean, let's add typehints for the newly added methods :)

Copy link
Contributor Author

@maidmaid maidmaid Dec 13, 2017

Choose a reason for hiding this comment

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

Done.

@maidmaid
Copy link
Contributor Author

@javiereguiluz Indeed, my current implementation provides only an unique style. The library which you mentionned allow to apply a different style between outside and inside borders. That doesn't look essential, but I like it. It can be useful for rendering a thinner separateur in the rows. I'm +1.

@nicolas-grekas nicolas-grekas added this to the 4.1 milestone Dec 12, 2017
@fabpot
Copy link
Member

fabpot commented Dec 12, 2017

The new style looks much better than the initial one. Looks great!

@maidmaid maidmaid force-pushed the console-pretty-table branch 3 times, most recently from 6ebc50d to d7eec74 Compare December 13, 2017 05:24
Copy link
Member

@chalasr chalasr left a comment

Choose a reason for hiding this comment

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

Awesome 👍

? array($this->style->getCrossingMidLeftChar(), $this->style->getCrossingChar(), $this->style->getCrossingMidRightChar())
: (self::SEPARATOR_TOP === $type
? array($this->style->getCrossingTopLeftChar(), $this->style->getCrossingTopMidChar(), $this->style->getCrossingTopRightChar())
: array($this->style->getCrossingBottomLeftChar(), $this->style->getCrossingBottomMidChar(), $this->style->getCrossingBottomRightChar()))
Copy link
Member

Choose a reason for hiding this comment

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

this nesting of ternary operators are hard to read IMO. I suggest using a if/elseif/else instead (and btw, this will also avoid the need to allocate arrays holding values just to unpack it immediately)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it better now?

* </code>
*
* @param string $cross Crossing char (see #0 of example)
* @param string|null $topLeft Top left char (see #1 of example), equal to $cross if undefined
Copy link
Member

Choose a reason for hiding this comment

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

if null. there is no undefined in PHP (E_TOO_MUCH_JAVASCRIPT 😄 ?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* Gets crossing top right char.
*
* @return string $crossingTopRightChar
*/
Copy link
Member

Choose a reason for hiding this comment

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

You probably added it for consistency, but please remove this docblock as it does not give more info than the signature itself, same for next ones below.

Copy link
Contributor Author

@maidmaid maidmaid Dec 16, 2017

Choose a reason for hiding this comment

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

Yes, it was for consistency with others methods. Docblocks removed.

@@ -132,6 +139,127 @@ public function getCrossingChar()
return $this->crossingChar;
Copy link
Contributor

Choose a reason for hiding this comment

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

you should deprecate getCrossingChar() and setCrossingChar()

Copy link
Contributor Author

@maidmaid maidmaid Dec 16, 2017

Choose a reason for hiding this comment

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

I deprecated setCrossingChar(). But not the getter which is always used as-is.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's the point of a deprecation. Update the calls and trigger a deprecation message. :}

*
* @return $this
*/
public function setCrossingChars(string $cross, string $topLeft = null, string $topMid = null, string $topRight = null, string $midRight = null, string $bottomRight = null, string $bottomMid = null, string $bottomLeft = null, string $midLeft = null): self
Copy link
Contributor

Choose a reason for hiding this comment

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

imo I would rather use ?string as @javiereguiluz said (or even not nullable string) and not take crossingChar. This methid should be called with $this->setCrossingChars($cross, $cross, ...); (and thus slowly deprecate crossingChar)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure to understand why use nullable string here... Could you to be more accurate please?

Copy link
Member

@javiereguiluz javiereguiluz Dec 16, 2017

Choose a reason for hiding this comment

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

Because ?string $topLeft looks better than string $topLeft = null, it's more concise, and the ?string feature was introduced in modern PHP versions precisely to avoid doing string ... = null

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mmh I'm not sure that ?string $topLeft replaces string $topLeft = null. ?string simply allows string and null value, but it doesn't set a null default value.

function f(?string $p) {}
f(); // Uncaught Error: Too few arguments to function f(), 0 passed in...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@Taluu Taluu Dec 16, 2017

Choose a reason for hiding this comment

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

Hum, didn't see the 0 in the schema, so my bad for the removal. But I still think that allowing a null value for the rest is not really good, and you should specify a value for all these other edges.

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, you CAN use the crossingChar for ALL the edges, but it shouldn't be implied if no value is given. Hence the "not allowing null values", so nothing too implicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

allowing a null value for the rest is not really good

I think that the first param $crossingChar can be used as generic crossing char:

$style->setCrossingChars('+');
// vs
$style->setCrossingChars('+', '+', '+', '+', '+', '+', '+', '+', '+');

Copy link
Contributor

Choose a reason for hiding this comment

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

i'd add this method above getCrossingChar

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ro0NL Moved.

@maidmaid maidmaid force-pushed the console-pretty-table branch 3 times, most recently from 650c922 to a701379 Compare December 16, 2017 09:47
*/
public function setCrossingChar($crossingChar)
{
@trigger_error(sprintf('%s() is deprecated since version 4.1 and will be removed in 5.0. Use setCrossingChars() instead.', __METHOD__), E_USER_DEPRECATED);

$this->crossingChar = $crossingChar;
Copy link
Contributor

Choose a reason for hiding this comment

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

should call $this->setCrossingChars($crossingChar); to update all properties

perhaps consider to not deprecate this method and make args in setCrossingChars required instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. Oups, bad rebase. It's fixed.
  2. Personally I prefer with optional args. Does this [Console] Make pretty the box style table #25456 (comment) convince you?

Copy link
Contributor Author

@maidmaid maidmaid Dec 16, 2017

Choose a reason for hiding this comment

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

Mmh finally, I have changed my opinion :) I think that setCrossingChar() can be conserved and used as a shortcut of setCrossingChars(). Moreover, that simplifies a lot this PR. Could you check my second commit? If you disagree, I can remote it.

Copy link
Contributor

Choose a reason for hiding this comment

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

If you keeo the setCrossingChar, then maybe you should add setTopLeft, and so on. And then get rid of setCrossingChars.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. If you don't use a generic crossing char by setting setCrossingChar(), you have to set all kinds of crossing char. And it's better if we can do it with only 1 call of setCrossingChars() instead 9 different calls (1 cross + 4 corners + 4 mids).

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't the idea of this PR to deprecate the "generic crossing char", in favor of using the specific ones ? The setCorssingChar should be imo just for the 0 (any "crossroad" delimiters). Using it as a generic should be deprecated.

Copy link
Contributor Author

@maidmaid maidmaid Dec 17, 2017

Choose a reason for hiding this comment

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

It was. But the #25456 (comment) of @ro0NL looks relevant:

// we can set specific chars:
setCrossingChars('', '', '', '', '', '', '', '', '');

// and we could also set generic char (useful for no-unicode):
setCrossingChar('+');

// without this last one, we should write:
setCrossingChars('+', '+', '+', '+', '+', '+', '+', '+', '+');

*
* @return $this
*/
public function setCrossingChars(string $cross, string $topLeft = null, string $topMid = null, string $topRight = null, string $midRight = null, string $bottomRight = null, string $bottomMid = null, string $bottomLeft = null, string $midLeft = null): self
Copy link
Contributor

Choose a reason for hiding this comment

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

i'd add this method above getCrossingChar

Copy link
Contributor

@ro0NL ro0NL left a comment

Choose a reason for hiding this comment

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

┌─────────────┐
| lookin good |
└─────────────┘

*/
public function setCrossingChar($crossingChar)
{
$this->crossingChar = $crossingChar;
@trigger_error(sprintf('%s() is deprecated since version 4.1 and will be removed in 5.0. Use setCrossingChars() instead.', __METHOD__), E_USER_DEPRECATED);
Copy link
Contributor

Choose a reason for hiding this comment

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

The method "%s()" is ... (note the quotes.. we want those :))

@maidmaid
Copy link
Contributor Author

(@ro0NL For generating your message review, I hope that you have used:

(new Table(new ConsoleOutput()))->setStyle('box')->setRows([['lookin good']])->render();

😄)

@maidmaid
Copy link
Contributor Author

maidmaid commented Jan 5, 2018

@stof Do we need more changes with this PR?

@maidmaid
Copy link
Contributor Author

Does this PR need some work still? (Travis failure not related)

Copy link
Contributor

@ro0NL ro0NL left a comment

Choose a reason for hiding this comment

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

minor comments :)

*/
public function setCrossingChar($crossingChar)
{
$this->crossingChar = $crossingChar;
@trigger_error(sprintf('%s() is deprecated since Symfony 4.1 and will be removed in 5.0. Use setDefaultCrossingChar() instead.', __METHOD__), E_USER_DEPRECATED);
Copy link
Contributor

Choose a reason for hiding this comment

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

Method "%s()" is ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

/**
* Sets crossing character.
*
* @param string $crossingChar
*
* @return $this
*
* @deprecated since Symfony 4.1, to be removed in 5.0. Use {@link setDefaultCrossingChar()} instead.
Copy link
Contributor

Choose a reason for hiding this comment

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

{@link method()} renders OK after compile? not sure it's needed / consistent:

https://github.com/symfony/symfony/search?l=PHP&q=%40deprecated+use+instead&type=&utf8=%E2%9C%93

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks good :) and often used in the code base.
screenshot from 2018-03-12 10-35-25

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(annex comment: {@link method()} is not rendered on api.symfony.com. E.g. https://api.symfony.com/3.4/Symfony/Bundle/SecurityBundle/Security/FirewallContext.html#method_getContext)

Copy link
Member

Choose a reason for hiding this comment

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

I would remove the @link here as we've never done that before elsewhere AFAIK.

Copy link
Contributor Author

@maidmaid maidmaid Mar 14, 2018

Choose a reason for hiding this comment

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

It's quite used in fact (e.g. on 3.4, more than 300 occurrences whose 13 in a @deprecated annotation) and it makes sense here IMO. Sure?

Copy link
Member

Choose a reason for hiding this comment

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

ok let's keep like this then :)

@maidmaid maidmaid force-pushed the console-pretty-table branch from f60296d to 528eacd Compare March 12, 2018 00:36
@javiereguiluz javiereguiluz added the ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" label Mar 12, 2018
@@ -132,6 +194,46 @@ public function getCrossingChar()
return $this->crossingChar;
}

public function getCrossingTopRightChar(): string
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need these getters? I can't picture a use case for these.

Copy link
Member

Choose a reason for hiding this comment

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

I agree with @ostrolucky, I would remove all the getters.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But getters are used in Table class for rendering, they can't be removed.

Copy link
Contributor

@ostrolucky ostrolucky Mar 14, 2018

Choose a reason for hiding this comment

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

Indeed

Copy link
Contributor

@ogizanagi ogizanagi Mar 14, 2018

Choose a reason for hiding this comment

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

I fear I'll might be the only one, but I'd rather use a single getter to get them all at once (from topLeft to midLeft).

Copy link
Member

Choose a reason for hiding this comment

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

+1 for @ogizanagi's idea. And let's mark it as internal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Member

@fabpot fabpot left a comment

Choose a reason for hiding this comment

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

If this new style works on all OSes (including Windows), I would switch the default table theme to the new one.

* Sets crossing characters.
*
* Example:
* <code>
Copy link
Member

Choose a reason for hiding this comment

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

We are not using HTML in desc, so this should be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

<code> tag is sometimes used yes (on master, 17 occurrences). This code-description can be useful IMO.

* @param string $bottomLeft Bottom left char (see #7 of example)
* @param string $midLeft Mid left char (see #8 of example)
*
* @return $this
Copy link
Member

Choose a reason for hiding this comment

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

Can be removed as the method signature already document this explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

/**
* Sets crossing character.
*
* @param string $crossingChar
*
* @return $this
*
* @deprecated since Symfony 4.1, to be removed in 5.0. Use {@link setDefaultCrossingChar()} instead.
Copy link
Member

Choose a reason for hiding this comment

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

I would remove the @link here as we've never done that before elsewhere AFAIK.

@@ -132,6 +194,46 @@ public function getCrossingChar()
return $this->crossingChar;
}

public function getCrossingTopRightChar(): string
Copy link
Member

Choose a reason for hiding this comment

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

I agree with @ostrolucky, I would remove all the getters.

@maidmaid
Copy link
Contributor Author

maidmaid commented Mar 14, 2018

including Windows

It's supposed to work with DOS too (cf https://en.wikipedia.org/wiki/Box-drawing_character#DOS).

I would switch the default table theme to the new one

Yes! But switching to the new theme breaks some tests and it's more complicated than expected. I suggest to do that in an another PR.

@maidmaid maidmaid force-pushed the console-pretty-table branch from 528eacd to 59f8464 Compare March 14, 2018 10:44
*/
public function setCrossingChar($crossingChar)
{
$this->crossingChar = $crossingChar;
@trigger_error(sprintf('Method %s() is deprecated since Symfony 4.1 and will be removed in 5.0. Use setDefaultCrossingChar() instead.', __METHOD__), E_USER_DEPRECATED);
Copy link
Contributor

Choose a reason for hiding this comment

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

and will be removed in 5.0 should be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@fabpot
Copy link
Member

fabpot commented Mar 17, 2018

Thank you @maidmaid.

@fabpot fabpot merged commit 41f52b3 into symfony:master Mar 17, 2018
fabpot added a commit that referenced this pull request Mar 17, 2018
This PR was merged into the 4.1-dev branch.

Discussion
----------

[Console] Make pretty the `box` style table

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | /
| License       | MIT
| Doc PR        | /

The console component is the 2nd most popular Symfony component with 70M of downloads. I think such composant has to provide faultless tables, with perfect management of borders, especially since the new `box` style table has been merged (cf #25301).

![screenshot from 2017-12-12 18-47-34](https://user-images.githubusercontent.com/4578773/33876488-6e1dc81c-df71-11e7-924f-d5e8078d957f.png)

Commits
-------

41f52b3 Make pretty the `box` style table
@robfrawley
Copy link
Contributor

robfrawley commented Mar 18, 2018

@maidmaid This looks absolutely amazing! I'm excited to see more feature/improvement changes for the console component's output handling; this is an excellent addition. Thanks for the work to get it done!

symfony-splitter pushed a commit to symfony/console that referenced this pull request Mar 30, 2018
This PR was merged into the 4.1-dev branch.

Discussion
----------

[Console] Add box-double table style

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | symfony/symfony#25456 (review)
| License       | MIT
| Doc PR        | /

In symfony/symfony#25456 (review) @javiereguiluz suggested to have a complete configuration for style table. It was a nice idea, but not yet implemented. The box-drawing characters allow to combine different styles (like double/single lines). This PR give the possibility to use them.

The previous symfony/symfony#25456 introduced the box-drawing characters; this PR exploits all their strength.

![image](https://user-images.githubusercontent.com/4578773/38136596-d8f4f46c-3462-11e8-9a0d-dcfae6039d18.png)

See https://gist.github.com/maidmaid/3eb55afc4f2857cae89d7ac43d7943ae for some examples.

Commits
-------

463f986c28 Add box-double table style
fabpot added a commit that referenced this pull request Mar 30, 2018
This PR was merged into the 4.1-dev branch.

Discussion
----------

[Console] Add box-double table style

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #25456 (review)
| License       | MIT
| Doc PR        | /

In #25456 (review) @javiereguiluz suggested to have a complete configuration for style table. It was a nice idea, but not yet implemented. The box-drawing characters allow to combine different styles (like double/single lines). This PR give the possibility to use them.

The previous #25456 introduced the box-drawing characters; this PR exploits all their strength.

![image](https://user-images.githubusercontent.com/4578773/38136596-d8f4f46c-3462-11e8-9a0d-dcfae6039d18.png)

See https://gist.github.com/maidmaid/3eb55afc4f2857cae89d7ac43d7943ae for some examples.

Commits
-------

463f986 Add box-double table style
@fabpot fabpot mentioned this pull request May 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Console Feature ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" Status: Reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.