Skip to content
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

Tabular alignment #1962

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open

Tabular alignment #1962

wants to merge 47 commits into from

Conversation

justinpombrio
Copy link
Collaborator

@justinpombrio justinpombrio commented May 8, 2024

Use tabular alignment for printing YSH lists and BashArrays. Runs in linear time.

The behavior is to use tabular alignment so long as all elements can be printed flat within some fixed max column-width (current 15). All columns are given the same width, even if some columns could be smaller.

For examples of how this looks, see the unit tests:

https://github.com/oilshell/oil/blob/4eecd36bad9df31b2526410245272b83c6d871a3/data_lang/pretty_test.txt

@justinpombrio justinpombrio requested a review from andychu May 8, 2024 19:33
@justinpombrio justinpombrio marked this pull request as ready for review May 9, 2024 17:11
@andychu
Copy link
Contributor

andychu commented May 9, 2024

Hm is the intention to do dicts as well? I think we talked about this on Zulip, but I'm not sure what the conclusion is

I think it looks better for an array of numbers

The nested test cases look a little weird, but maybe those are uncommon cases

> "dicen", "pío",
> "pío", "pío"
> ],
> [
Copy link
Contributor

Choose a reason for hiding this comment

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

This one seems to look weirder than it used to? I wonder if having the rule only apply to "leaf" containers, i.e. containers that don't have any containers, would help

Although arguably you may want to format dicts like

{k: [1,2], k2: [3,4], ... }

etc

@justinpombrio
Copy link
Collaborator Author

Hm is the intention to do dicts as well? I think we talked about this on Zulip, but I'm not sure what the conclusion is

I'd suggest not doing it for dicts, because (i) it would need to align both the keys and the values, which might look stranger, and (ii) since you're aligning both, they'll tend to be longer, making dicts use the tabular layout less often, making it less useful and more surprising to users; and (iii) I've seen tabular alignment for lists elsewhere, but never for dicts.

The nested test cases look a little weird, but maybe those are uncommon cases

You mean the formatting of [1, [2, [3, [4, [5, [6]]]]]]? That is not using the new tabular alignment (there aren't enough elements for it to get chosen by the PP algorithm), it's behaving the same as before. The reason it looks worse than before is because I changed the test cases from having an indentation level of 2 to 4, to match the real behavior.

I agree that [1, [2, [3, [4, [5, [6]]]]]] formats poorly. I added it because it's a case where Wadler-style printing doesn't work well. Though it's only this bad when you have a (hopefully rare) combination of elements smaller than the indentation level (4 chars) and deep nesting and the nesting is non-uniform.

@andychu
Copy link
Contributor

andychu commented May 13, 2024

Sorry for the delayed response

Let me poke at this a bit more tonight, I think it's probably fine but I thought it may be weird if we do tabular alignment of lists but not dicts

But I can see they are slightly different

@andychu
Copy link
Contributor

andychu commented May 13, 2024

Oh one thing that could help us decide is to do the ASDL formatting, because we actually have real testdata for that, not synthetic testdata

e.g. we can do osh -n configure and then eyeball it to make sure that the AST prints/fits nicely, based on real data


Though it's also true there are no dicts in that case really! And maybe no arrays of numbers, so we can treat it like a particular use case (that we use ourselves)

Copy link
Contributor

@andychu andychu left a comment

Choose a reason for hiding this comment

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

Thanks, I tested this out and it seems nice!

I bumped the width to 16 to accomodate floats, and added a little demo


max_flat_len = items[0].measure.flat
seq = [items[0]]
for item in items[1:]:
Copy link
Contributor

Choose a reason for hiding this comment

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

We are paying attention to GC objects, so I would remove the items[1:] slice and write it like

for i, item in enumerate(items):
  if i != 0:
    seq.append(_Text(...))
    ...

I use that idiom fairly often for "in between" separators, and I think it's pretty readable

sep_width = _StrWidth(sep)
if max_flat_len + sep_width + 1 <= self.max_tabular_width:
tabular_seq = [] # type: List[MeasuredDoc]
for item in items[:-1]:
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto here, I think it makes sense to test i != n - 1 , should be about the same number of lines of code

(Or i != 0 if possible)

second "tabular' style is used if the flat width of all items is no
greater than `self.max_tabular_width`. The third "multi line" style is
used otherwise.
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe write something about why we're not using a more obvious rule? It's expensive?

e.g. as long as 2 items fit on every line, it could be tabular, etc.

e.g. if I have a screen of 80, and I have 10 strings of length no more 30, then 2 can fit on every line

I can sorta see why that requires a search, but it's probably good to document it

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.

None yet

2 participants