brittany
brittany copied to clipboard
Add support for sorting and aligning LANGUAGE pragmas
I'd like to see similar behaviour to stylish-haskell
where the pragmas are sorted, nub
ed, and aligned. I started looking into this a bit and the pragmas are stored as comments, so this might be a little complicated. @lspitzner I'd love some guidance on how to get started on this.
thanks for the interest!
my first thought was: i bet there is a quick and dirty approach that works for 90% of cases that just works on the un-parsed lines and uses some variation of span ("{-# LANGUAGE" `isPrefixOf`)
but after thinking a bit i think it might break quickly, see point 4) below.
Before talking any implementation, I would like to nail down the desired behaviour a bit more. Even for such a simple thing there are some corner-cases:
-
I guess we want per-block sorting (and uniq). I.e.
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}
turns into
{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}
-
We could treat "commented-out" ones like regular ones with respect to sorting:
-- {-# LANGUAGE MonadComprehensions #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecursiveDo #-}
turns into
{-# LANGUAGE LambdaCase #-} -- {-# LANGUAGE MonadComprehensions #-} {-# LANGUAGE RecursiveDo #-}
and also:
-
collapse commented/not commented pragmas:
-- {-# LANGUAGE LambdaCase #-} {-# LANGUAGE LambdaCase #-}
turns into
{-# LANGUAGE LambdaCase #-}
-
transpose pragma-of-list into list-of-pragma
{-# LANGUAGE LambdaCase, RecursiveDo, MonadComprehensions #-}
turns into
{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MonadComprehensions #-} {-# LANGUAGE RecursiveDo #-}
btw this is a good case against any line-based approach: the input might be
{-# LANGUAGE LambdaCase, RecursiveDo, MonadComprehensions #-}
-
Apart from commented-out-pragmas, other comments are treated like whitespace (and consequently break up blocks).
This includes any comments before at file start that precede pragmas.
I have somewhat intentionally omitted the alignment aspect again here, because it is another instance of "context sensitivity": Do we really want to touch all pragmas because we add -XGeneralizedNewtypeDeriving
? (Or whatever is the longest pragma :p)
Assuming we are roughly in agreement on this behaviour, I think the implementation is just a plain recursion over the list of comments in the annotation. Must gather elements of a "blocks" (as discussed above); blocks are identified by DPs; for each completed block: stash the DP of the first comment and replace it with DP (1,0)
, sort, uniq, then restore the DP of the (new) first comment to the stashed one; continue on remaining comments.
The task of taking apart the pragma-of-list almost is sufficient reason to use some proper parser, but plain List functions will work too. No strong opinion - e.g. the existing extractCommentConfigs
implementation is not pretty, but works without any additional dependencies *shrugs*, see https://github.com/lspitzner/brittany/blob/621e00bf3f24896d603978c3d4e5fd61dac3841a/src/Language/Haskell/Brittany/Internal.hs#L97-L114
Thanks @lspitzner - I'm also working on a PR for sorting import lists and it uses a similar stash, sort, uniq, restore approach. I'll give it a go and get back to you!
Any news on the progress of this?
Just adding an note that this should only be in effect for appropriate ColumnAlignMode
s :wink: