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
Vertically align tokens #41
Comments
@shwestrick Thinking about how to implement this. Instinctively, I want to compute the length of each column and (left or right) align by padding with spaces. However, I'm not sure how this would work with comments and non-atomic components (e.g., |
Yeah I've thought a bit about this and I'm not sure what the best solution is. The simplest solution, from the layout perspective, is something like datatype doc =
...
| Table of {numRows: int, numCols: int, elem: (int * int) -> token} And you could imagine augmenting it with padding/justification info, like a function But this kinda sucks for actually writing formatter cases. |
It might be possible to instead allow each element of the table to be a |
Personally I find this really difficult to read, because I look to the left to see where the next declaration begins, rather than at the names. This maybe isn't too bad? eqtype apple
and orange
datatype apple = Foo | Bar
and orange = Baz |
Hmm, yeah... I think we'd need to support at least a few tokens in a row ( datatype ('a, 'b) apple = Foo 'a | Bar of 'b
and orange = Baz of (int, int) apple |
Ah, I see. My eye tends to center around the sort/name, I think ( I wonder how each of our approaches fare as the length of type names vary. Some sample cases: datatype foo = Foo
and bar = Bar
(* left/left *)
datatype foo = Foo
and bar = Bar
(* right/left, right/right *)
datatype foo = Foo
and bar = Bar datatype ('a, 'b) apple = Foo
and orange = Bar
(* left/left *)
datatype ('a, 'b) apple = Foo
and orange = Bar
(* right/left *)
datatype ('a, 'b) apple = Foo
and orange = Bar
(* right/right *)
datatype ('a, 'b) apple = Foo
and orange = Bar datatype apple = Foo
and ('a, 'b) orange = Bar
(* left/left *)
datatype apple = Foo
and ('a, 'b) orange = Bar
(* right/left *)
datatype apple = Foo
and ('a, 'b) orange = Bar
(* right/right *)
datatype apple = Foo
and ('a, 'b) orange = Bar (Edit: for |
Just realizing - the left vs. right justification issue only arises in a few relatively uncommon cases for EDIT: |
Just remembered another use case for this (in specs): val twelve : int
and thirteen : int
(* formatted to *)
val twelve : int
and thirteen : int If values are declared together, should probably align their |
Perhaps also: type t =
{ apple : t
, watermelon : t
, orange : t
}
(* formatted to *)
type t =
{ apple : t
, watermelon : t
, orange : t
} |
@HarrisonGrodin I'm thinking we could try adding this to the interface val table: {numRows: int, numCols: int, elem: {row:int, col:int} -> doc} -> doc I'm picturing that each I don't think this would be too difficult to implement. But it leaves the question of whether or not it is usable for writing pretty cases. One hangup is that you would need to be careful to not put possibly rigid things inside a table. Thoughts? |
Here's one place where this would be a pain. val x : foo
val y : bar longbar very long bar
definitely needs multiple
lines bar
val z : baz Essentially this is a case of "wrapping" within a cell, but of course it's not the same semantics as table cell wrapping. |
This seems problematic to me; it seems important that all code have at least some autoformatted output. Forcible flattening sounds somewhat reasonable, although this probably shouldn't apply to the last (* should align ='s *)
val pat1 = exp1
and pat2 = exp2
val x =
case bar of
nil => 0
| x :: xs => x + prod xs
and foo = exp2 A similar issue shows up for many other |
Oh, just realized - we probably want nested tables, as long as they're nested only at the end of another table, in cases like this: type short =
{ label1 : t1
, label2 : t2
}
and veryveryverylong =
{ label3 : t3
, label4 : t4
, label5 : t5
} and this: case foo of
pat => 1
| longpat => (
case bar of
pat => 2
| longpat => 3
| longerpat => 4
)
| longerpat => 5 |
Well, keep in mind these are implementation details. It restricts how you use tables, not what the pretty-printer can do. If there was a runtime error due to rigid inside table, that would be a bug in the implementation of the pretty printer.
You can do this without changing the table definition. If the last doc shouldn't be flattened, then we can just take it out of the table, and prettify it separately.
More of an aesthetics point, but I think this is a great example of where we need to be careful with vertical alignment. The first equals definitely should not be way out there like that ;) |
Ohh, I see what you mean. 👍
Not sure I follow this - if the last doc in each row shouldn't be flattened, how could we insert it after each table row if the table was a single compound
Hmm... I can't decide if I agree or not! I like the principle that if definitions are given with |
Another case for potential alignment I was just thinking about - datatype foo =
Apple of int
| Pineapple of string
(* should perhaps be formatted to *)
datatype foo =
Apple of int
| Pineapple of string I think this is probably sensible, since it's dual to aligning the |
You would need to have in hand the last doc of the table anyway, in order to define what the elements of the table are. So all you need to do is just not give that particular doc to the table, and instead do something like
I think I agree only if the Actually, this might be a nice general principle: vertical alignment only when the aligned tokens are on adjacent lines. |
Think I might be missing something here; given
Hmm, that's interesting; I think I'm okay with either. (I still feel a bit of the symmetry across multiple lines, but your suggestion might be the less obscure style.) It would make table formatting easier, I suppose (given multiline rows, just display in sequence with no alignment?). What should happen if some of the type foo = int
and short =
{ label1 : t1
, label2 : t2
}
and veryveryverylong =
{ label3 : t3
, label4 : t4
, label5 : t5
} Should the first two case foo of
pat =>
long multiline expression
| longpat => 1
| longerpat => 2 I'm perfectly happy with always aligning the |
We should at least align delimiters, imo, e.g.:
I would also prefer right-aligning keywords before name definitions so names are aligned, e.g.:
Unsure if this is a popular opinion, though.
The text was updated successfully, but these errors were encountered: