Support IndentPolicyLeft #66
No reviewers
Labels
No Label
blocked: dependency
blocked: info-needed
bug
duplicate
enhancement
fixed in HEAD
help wanted
hs:arrows
hs:brackets
hs:classes
hs:comments
hs:do-notation
hs:guards
hs:lists
hs:operators
hs:patterns
hs:records
hs:types
invalid
language extension support
layouting
needs confirmation
priority: high
priority: low
question
revisit before next release
wontfix
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: hexagoxel/brittany#66
Loading…
Reference in New Issue
There is no content yet.
Delete Branch "indentpolicyleft"
Deleting a branch is permanent. Although the deleted branch may exist for a short time before cleaning up, in most cases it CANNOT be undone. Continue?
This PR introduces support for
IndentPolicyLeft
inbrittany
.This work has proceeded with the intent to couple
IndentPolicyLeft
withColumnAlignModeDisabled
to allow a context free formatting style forbrittany
. Decisions on syntactic form follow that philosophy. Tests have been added for this use case. They currently represent a fair amount of duplication, but that should be able to be reduced once inline format annotations are available.Actually there was less left in this batch of work then I realised.
This is ready for review.
For posterity this is addressing issues raised in: https://github.com/lspitzner/brittany/issues/56
In general this looks good. I still want to look at the different layouter changes in detail, and I won't do that today (even when the changes are relatively transparent).
But some first-glance stuff:
dev
branch. Shouldn't be too hard to fix though. Although the proper route is to add a commandline flag for indentpolicy and use the stuff from theinlineconfig
branch.. but that can be improved at a later point too.I just want to say that I would drop
hindent
forbrittany
in a heartbeat ifbrittany
never did any context-sensitive alignment. I feel likeghc-exactprint
is a more solid foundation thanhaskell-src-exts
, but at the same time I don't want code formatted as shown in #56. I can't speak to implementation details, but @eborden's test suite looks exactly like how I would format things by hand.Agreed. I have never found myself preferring context sensitive alignment.
I've looked through all changes; most are fine without further comments. I am not certain yet if all context-sensitive stuff is removed yet, but if there are remaining cases they can be fixed later.
Apart from the minor stuff I commented, the major annoyance is making this mergeable with the
dev
branch. There are some large conflicts already I noticed (but it looks worse than it is).I think a rebase will be easier to manage than a merge.
@ -481,0 +550,4 @@
]
)
, ( indentPolicy /= IndentPolicyLeft
, docLines
Please remove the duplication here. In the
IndentPolicyLeft
case, the docAlt can move further in, also removing some duplication.Doesn't the only-one-let-binder-case (above) also need adjustment?
Could use
docAltFilter
here too, just to .. stay consistent :DdocSetBaseAndIndent
there most likely produceshanging indentation(or at least) more-than-usual indentation. Probably need to disable this alt-branch, too.A bit of nitpicking: "context sensitive" is ambiguous, but the way i read it here, the only way to be truly context-insensitive would be to remove all
docAlt
nodes (or, equivalently, to disable all but one alternative in every case). Because only then depth in syntax-tree corresponds to indentation exactly, and only then changes to siblings have no chance of affecting the layout of any node. AndIndentPolicyLeft
is far from that, and it is not what we want either, see the extreme example of truly context-free layouting in my brittany rationale.What we want instead is a compromise between that and the "least newlines possible" layout. Of course the current default may not be the right compromise. Indeed, I am somewhat inclined to making the non-hanging-indentation layout the default. I just don't consider IndentPolicyLeft that different from a theoretical standpoint :p
I don't know if this is the right place to have this discussion, but for me at least "context free" layout means that some expression doesn't depend on the previous expression for its indentation. For example, this is "context sensitive" to me:
Whereas this is "context free":
In particular it doesn't mean that every expression is always formatted the same way. Line length is still a concern. But when something forces a newline, the indentation is always "one tab" rather than aligning with the thing above it.
As I said before, the examples/tests that @eborden added here are exactly how I want things formatted. If there's a term other than "context free" I should be using, I'll be happy to use it instead.
Ah, so only indentation, and only after newlines. I'd call this "allowing hanging indentation". Perhaps I have too much of the implementation in mind: "indentation after newlines" is just one of the choices of layouting. E.g. if the choices are 1) oneliner 2) multiline with hanging 3) multiline with default indentation, then even if you disable 2) the decision between 1 and 3 is "context sensitive" ("would this overflow 80 cols?" can only be answered in context, for pretty much the same definition of "context" you used.)
(All this does not stand in any way against merging this. I don't mind at all how the test file is named etc. The intend of the issue and the PR are clear and the addition is welcome.)
I've updated the code per your inline comments. Would you like me to rebase this over the
dev
branch and change the base of this PR?@eborden Well I need these branches merged one way or another. But I can see about the rebase myself, I probably have a better idea of how to handle the conflicts.
(The CI failure is nonsense afaict.)
Pushed the rebased branch to
eborden-indentpolicyleft
. I was hoping to be able to push directly to the PR.. but what i tried did not work.There are still two bad testcases. Also I think the stack build does not compile. (The travis CI script is still broken and won't report error correctly.)
@lspitzner I'll see about merging that branch into this today.
I should note that current dev branch (and the one i rebased onto) is slighly broken. nothing to do with the merge, but with the removal of
either
package.@lspitzner Do you always want PRs submitted against the
dev
branch? If so that might be a good thing to outline in a contributors section inREADME.md
.@eborden indeed, and i already added such a note to the readme a few days ago. bit late for this PR, but the rebase was still manageable :)
would you mind if i rebase again, just so we base this PR on a working commit?
@lspitzner Do you want me to give you access to my fork so you can rebase this branch specifically?
@lspitzner Added you as a collaborator.
great, lets see what the CI says. With some luck it will properly report things this time :)
Ok, that looks right this time; the test failures there are exactly what i see locally. And I think both are just mistakes of the testcases themselves, right?
Yup, that seems to be the case. I'll pull this and fix those up in a bit.
@ -59,0 +51,4 @@
LetStmt binds -> layoutLocalBinds binds >>= \case
Nothing -> docLit $ Text.pack "let" -- i just tested
-- it, and it is
-- indeed allowed.
Is there a simple way to enable this when the expression is actually a single line? That might be too much complexity thought 😄
@ -59,0 +51,4 @@
LetStmt binds -> layoutLocalBinds binds >>= \case
Nothing -> docLit $ Text.pack "let" -- i just tested
-- it, and it is
-- indeed allowed.
Like this? I think this works.. oh I broke the tests.
@ -59,0 +51,4 @@
LetStmt binds -> layoutLocalBinds binds >>= \case
Nothing -> docLit $ Text.pack "let" -- i just tested
-- it, and it is
-- indeed allowed.
But they highlight the changes. And looks approximately correct (although the test coverage is not to be trusted entirely.)
You could even say this is less complexity :)
@eborden you probably did not get notified when i commented on the diff comments. Any opinion on the last commit I added? Otherwise I'll assume this is ok and simply merge. (dev branch has diverged already again. not by much, but i really want this merged sooner rather than later.)
Oh woops. Sorry about that. That seems like a good approach. So will that fail if it can't force something into a single line?
Yeah. I'd phrase it as "it restricts the possible layouts for the argument-bridoc to those that fit in a single line" but that probably captures the same idea.
Awesome. That sounds perfect to me.
(a sequence of docLit, docSeparator and (docForceSingleLine x) for arbitrary x thereby only has layouts that are single-line as a whole.)
Great, consider it merged then (I'll wait for CI).
Thanks for the contribution!
I'll make a 0.9.0.0 release that will include this in the next days.
Sweet, thanks for helping me through it!
FYI I re-formatted a medium-sized project with
brittany
and it went great:e88f4be14d
?diff=split&w=1Notes when compared to
hindent
:brittany
puts::
on a new line instead of on the same line as the identifier.x\n :: a
versusx ::\n a
. I prefer the way thatbrittany
does it.brittany
uses a lot fewer newlines without making things cramped, particularly after->
,=
, and<-
.brittany
puts operators at the beginning of the line, which is pretty much always what I want.brittany
indents afterlet
instead of aligning. Yay!There were two things I noticed that felt weird. First,
brittany
always indents afterlet
even if it would fit on one line. Also, it does the same thing afterin
. For example:Not really a problem. It eats up some vertical space in the name of consistency. The other weird thing is long expression inside parentheses.
This feels weird but it's not really a problem. It's more consistent with multi-line tuples or lists, but I don't think I've ever seen Haskell code formatted like this before. On the other hand, it always bugged me that
hindent
formatted tuples like this:So maybe the problem is me 😄
Hmm that
let
issue can likely be fixed. There is logic in the statement version that could be ported to the expression form. Could you open an issue?👉 https://github.com/lspitzner/brittany/issues/73