Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Latest commit

 

History

History
1808 lines (1405 loc) · 31.6 KB

TESTS.md

File metadata and controls

1808 lines (1405 loc) · 31.6 KB

Introduction

This file is a test suite. Each section maps to an HSpec test, and each line that is followed by a Haskell code fence is tested to make sure re-formatting that code snippet produces the same result.

You can browse through this document to see what HIndent's style is like, or contribute additional sections to it, or regression tests.

Modules

Empty module

Double shebangs

#!/usr/bin/env stack
#!/usr/bin/env stack
main = pure ()

Extension pragmas

{-# LANGUAGE TypeApplications #-}

fun @Int 12

Module header

module X where

x = 1

Exports

module X
  ( x
  , y
  , Z
  , P(x, z)
  ) where

Exports, indentation 4

module X
    ( x
    , y
    , Z
    , P(x, z)
    ) where

Imports

Import lists

import Data.Text
import Data.Text
import qualified Data.Text as T
import qualified Data.Text (a, b, c)
import Data.Text (a, b, c)
import Data.Text hiding (a, b, c)

Sorted

import B
import A
import A
import B

Explicit imports - capitals first (typeclasses/types), then operators, then identifiers

import qualified MegaModule as M ((>>>), MonadBaseControl, void, MaybeT(..), join, Maybe(Nothing, Just), liftIO, Either, (<<<), Monad(return, (>>=), (>>)))
import qualified MegaModule as M
  ( Either
  , Maybe(Just, Nothing)
  , MaybeT(..)
  , Monad((>>), (>>=), return)
  , MonadBaseControl
  , (<<<)
  , (>>>)
  , join
  , liftIO
  , void
  )

Pretty import specification

import A hiding
  ( foobarbazqux
  , foobarbazqux
  , foobarbazqux
  , foobarbazqux
  , foobarbazqux
  , foobarbazqux
  , foobarbazqux
  )

import Name hiding ()

import {-# SOURCE #-} safe qualified Module as M hiding (a, b, c, d, e, f)

Declarations

Type declaration

type EventSource a = (AddHandler a, a -> IO ())

Type declaration with infix promoted type constructor

fun1 :: Def ('[ Ref s (Stored Uint32), IBool] 'T.:-> IBool)
fun1 = undefined

fun2 :: Def ('[ Ref s (Stored Uint32), IBool] ':-> IBool)
fun2 = undefined

Instance declaration without decls

instance C a

Instance declaration with decls

instance C a where
  foobar = do
    x y
    k p

Symbol class constructor in instance declaration

instance Bool :?: Bool

instance (:?:) Int Bool

GADT declarations

data Ty :: (* -> *) where
  TCon
    :: { field1 :: Int
       , field2 :: Bool}
    -> Ty Bool
  TCon' :: (a :: *) -> a -> Ty a

Expressions

Lazy patterns in a lambda

f = \ ~a -> undefined
-- \~a yields parse error on input ‘\~’

Bang patterns in a lambda

f = \ !a -> undefined
-- \!a yields parse error on input ‘\!’

List comprehensions, short

map f xs = [f x | x <- xs]

List comprehensions, long

defaultExtensions =
  [ e
  | EnableExtension {extensionField1 = extensionField1} <-
      knownExtensions knownExtensions
  , let a = b
    -- comment
  , let c = d
    -- comment
  ]

List comprehensions with operators

defaultExtensions =
  [e | e@EnableExtension {} <- knownExtensions] \\
  map EnableExtension badExtensions

Parallel list comprehension, short

zip xs ys = [(x, y) | x <- xs | y <- ys]

Parallel list comprehension, long

fun xs ys =
  [ (alphaBetaGamma, deltaEpsilonZeta)
  | x <- xs
  , z <- zs
  | y <- ys
  , cond
  , let t = t
  ]

Record, short

getGitProvider :: EventProvider GitRecord ()
getGitProvider =
  EventProvider {getModuleName = "Git", getEvents = getRepoCommits}

Record, medium

commitToEvent :: FolderPath -> TimeZone -> Commit -> Event.Event
commitToEvent gitFolderPath timezone commit =
  Event.Event
    {pluginName = getModuleName getGitProvider, eventIcon = "glyphicon-cog"}

Record, long

commitToEvent :: FolderPath -> TimeZone -> Commit -> Event.Event
commitToEvent gitFolderPath timezone commit =
  Event.Event
    { pluginName = getModuleName getGitProvider
    , eventIcon = "glyphicon-cog"
    , eventDate = localTimeToUTC timezone (commitDate commit)
    }

Record with symbol constructor

f = (:..?) {}

Record with symbol field

f x = x {(..?) = wat}

g x = Rec {(..?)}

Cases

strToMonth :: String -> Int
strToMonth month =
  case month of
    "Jan" -> 1
    "Feb" -> 2
    _ -> error $ "Unknown month " ++ month

Operators, bad

x =
  Value <$> thing <*> secondThing <*> thirdThing <*> fourthThing <*>
  Just thisissolong <*>
  Just stilllonger <*>
  evenlonger

Operators, good

x =
  Value <$> thing <*> secondThing <*> thirdThing <*> fourthThing <*>
  Just thisissolong <*> Just stilllonger <*> evenlonger

Operator with do

for xs $ do
  left x
  right x

Operator with lambda

for xs $ \x -> do
  left x
  right x

Operator with lambda-case

for xs $ \case
  Left x -> x

Operator in parentheses

cat = (++)

Symbol data constructor in parentheses

cons = (:)

cons' = (:|)

n+k patterns

f (n+5) = 0

Binary symbol data constructor in pattern

f (x :| _) = x

f' ((:|) x _) = x

f'' ((Data.List.NonEmpty.:|) x _) = x

g (x:xs) = x

g' ((:) x _) = x

Type application

{-# LANGUAGE TypeApplications #-}

fun @Int 12

Transform list comprehensions

list =
  [ (x, y, map the v)
  | x <- [1 .. 10]
  , y <- [1 .. 10]
  , let v = x + y
  , then group by v using groupWith
  , then take 10
  , then group using permutations
  , t <- concat v
  , then takeWhile by t < 3
  ]

Type families

type family Id a

Type family annotations

type family Id a :: *

Type family instances

type instance Id Int = Int

Type family dependencies

type family Id a = r | r -> a

Binding implicit parameters

f =
  let ?x = 42
   in f

Closed type families

type family Closed (a :: k) :: Bool where
  Closed x = 'True

Template Haskell

Expression brackets

add1 x = [|x + 1|]

Pattern brackets

mkPat = [p|(x, y)|]

Type brackets

foo :: $([t|Bool|]) -> a

Quoted data constructors

cons = '(:)

Pattern splices

f $pat = ()

g =
  case x of
    $(mkPat y z) -> True
    _ -> False

Type signatures

Long argument list should line break

longLongFunction ::
     ReaderT r (WriterT w (StateT s m)) a
  -> StateT s (WriterT w (ReaderT r m)) a

Class constraints should leave :: on same line

-- see https://github.com/chrisdone/hindent/pull/266#issuecomment-244182805
fun ::
     (Class a, Class b)
  => fooooooooooo bar mu zot
  -> fooooooooooo bar mu zot
  -> c

Class constraints

fun :: (Class a, Class b) => a -> b -> c

Symbol class constructor in class constraint

f :: (a :?: b) => (a, b)
f' :: ((:?:) a b) => (a, b)

Tuples

fun :: (a, b, c) -> (a, b)

Quasiquotes in types

fun :: [a|bc|]

Default signatures

-- https://github.com/chrisdone/hindent/issues/283
class Foo a where
  bar :: a -> a -> a
  default bar :: Monoid a =>
    a -> a -> a
  bar = mappend

Implicit parameters

f :: (?x :: Int) => Int

Symbol type constructor

f :: a :?: b
f' :: (:?:) a b

Promoted list (issue #348)

a :: A '[ 'True]
a = undefined

-- nested promoted list with multiple elements.
b :: A '[ '[ 'True, 'False], '[ 'False, 'True]]
b = undefined

Promoted list with a tuple (issue #348)

a :: A '[ '( a, b, c, d)]
a = undefined

-- nested promoted tuples.
b :: A '[ '( 'True, 'False, '[], '( 'False, 'True))]
b = undefined

Prefix promoted symbol type constructor

a :: '(T.:->) 'True 'False
b :: (T.:->) 'True 'False
c :: '(:->) 'True 'False
d :: (:->) 'True 'False

Function declarations

Prefix notation for operators

(+) :: Num a => a -> a -> a
(+) a b = a

Where clause

sayHello = do
  name <- getLine
  putStrLn $ greeting name
  where
    greeting name = "Hello, " ++ name ++ "!"

Guards and pattern guards

f x
  | x <- Just x
  , x <- Just x =
    case x of
      Just x -> e
  | otherwise = do e
  where
    x = y

Multi-way if

x =
  if | x <- Just x,
       x <- Just x ->
       case x of
         Just x -> e
         Nothing -> p
     | otherwise -> e

Case inside a where and do

g x =
  case x of
    a -> x
  where
    foo =
      case x of
        _ -> do
          launchMissiles
      where
        y = 2

Let inside a where

g x =
  let x = 1
   in x
  where
    foo =
      let y = 2
          z = 3
       in y

Lists

exceptions = [InvalidStatusCode, MissingContentHeader, InternalServerError]

exceptions =
  [ InvalidStatusCode
  , MissingContentHeader
  , InternalServerError
  , InvalidStatusCode
  , MissingContentHeader
  , InternalServerError
  ]

Long line, function application

test = do
  alphaBetaGamma deltaEpsilonZeta etaThetaIota kappaLambdaMu nuXiOmicron piRh79
  alphaBetaGamma deltaEpsilonZeta etaThetaIota kappaLambdaMu nuXiOmicron piRho80
  alphaBetaGamma
    deltaEpsilonZeta
    etaThetaIota
    kappaLambdaMu
    nuXiOmicron
    piRhoS81

Long line, tuple

test
  (alphaBetaGamma, deltaEpsilonZeta, etaThetaIota, kappaLambdaMu, nuXiOmicro79)
  (alphaBetaGamma, deltaEpsilonZeta, etaThetaIota, kappaLambdaMu, nuXiOmicron80)
  ( alphaBetaGamma
  , deltaEpsilonZeta
  , etaThetaIota
  , kappaLambdaMu
  , nuXiOmicronP81)

Long line, tuple section

test
  (, alphaBetaGamma, , deltaEpsilonZeta, , etaThetaIota, kappaLambdaMu, nu79, )
  (, alphaBetaGamma, , deltaEpsilonZeta, , etaThetaIota, kappaLambdaMu, , n80, )
  (
  , alphaBetaGamma
  ,
  , deltaEpsilonZeta
  ,
  , etaThetaIota
  , kappaLambdaMu
  ,
  , nu81
  ,)

Record syntax

Pattern matching, short

fun Rec {alpha = beta, gamma = delta, epsilon = zeta, eta = theta, iota = kappa} = do
  beta + delta + zeta + theta + kappa

Pattern matching, long

fun Rec { alpha = beta
        , gamma = delta
        , epsilon = zeta
        , eta = theta
        , iota = kappa
        , lambda = mu
        } =
  beta + delta + zeta + theta + kappa + mu + beta + delta + zeta + theta + kappa

Symbol constructor, short

fun ((:..?) {}) = undefined

Symbol constructor, long

fun (:..?) { alpha = beta
           , gamma = delta
           , epsilon = zeta
           , eta = theta
           , iota = kappa
           , lambda = mu
           } =
  beta + delta + zeta + theta + kappa + mu + beta + delta + zeta + theta + kappa

Symbol field

f (X {(..?) = x}) = x

Punned symbol field

f' (X {(..?)}) = (..?)

Johan Tibell compatibility checks

Basic example from Tibbe's style

sayHello :: IO ()
sayHello = do
  name <- getLine
  putStrLn $ greeting name
  where
    greeting name = "Hello, " ++ name ++ "!"

filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:xs)
  | p x = x : filter p xs
  | otherwise = filter p xs

Data declarations

data Tree a
  = Branch !a !(Tree a) !(Tree a)
  | Leaf

data Tree a
  = Branch
      !a
      !(Tree a)
      !(Tree a)
      !(Tree a)
      !(Tree a)
      !(Tree a)
      !(Tree a)
      !(Tree a)
  | Leaf

data HttpException
  = InvalidStatusCode Int
  | MissingContentHeader

data Person =
  Person
    { firstName :: !String -- ^ First name
    , lastName :: !String -- ^ Last name
    , age :: !Int -- ^ Age
    }

data Expression a
  = VariableExpression
      { id :: Id Expression
      , label :: a
      }
  | FunctionExpression
      { var :: Id Expression
      , body :: Expression a
      , label :: a
      }
  | ApplyExpression
      { func :: Expression a
      , arg :: Expression a
      , label :: a
      }
  | ConstructorExpression
      { id :: Id Constructor
      , label :: a
      }

Spaces between deriving classes

-- From https://github.com/chrisdone/hindent/issues/167
data Person =
  Person
    { firstName :: !String -- ^ First name
    , lastName :: !String -- ^ Last name
    , age :: !Int -- ^ Age
    }
  deriving (Eq, Show)

Hanging lambdas

bar :: IO ()
bar =
  forM_ [1, 2, 3] $ \n -> do
    putStrLn "Here comes a number!"
    print n

foo :: IO ()
foo =
  alloca 10 $ \a ->
    alloca 20 $ \b ->
      cFunction fooo barrr muuu (fooo barrr muuu) (fooo barrr muuu)

Comments

Comments within a declaration

bob -- after bob
 =
  foo -- next to foo
  -- line after foo
    (bar
       foo -- next to bar foo
       bar -- next to bar
     ) -- next to the end paren of (bar)
    -- line after (bar)
    mu -- next to mu
    -- line after mu
    -- another line after mu
    zot -- next to zot
    -- line after zot
    (case casey -- after casey
           of
       Just -- after Just
        -> do
         justice -- after justice
          *
           foo
             (blah * blah + z + 2 / 4 + a - -- before a line break
              2 * -- inside this mess
              z /
              2 /
              2 /
              aooooo /
              aaaaa -- bob comment
              ) +
           (sdfsdfsd fsdfsdf) -- blah comment
         putStrLn "")
    [1, 2, 3]
    [ 1 -- foo
    , ( 2 -- bar
      , 2.5 -- mu
       )
    , 3
    ]
    -- in the end of the function
  where
    alpha = alpha
    -- between alpha and beta
    beta = beta
    -- after beta

foo = 1 -- after foo

gamma = do
  delta
  epsilon
  -- in the end of a do-block 1

gamma = do
  delta
  epsilon
  -- the very last block is detected differently

Doesn't work yet (wrong comment position detection)

gamma = do
  -- in the beginning of a do-block
  delta
  where
    -- before alpha
    alpha = alpha

Haddock comments

-- | Module comment.
module X where

-- | Main doc.
main :: IO ()
main = return ()

data X
  = X -- ^ X is for xylophone.
  | Y -- ^ Y is for why did I eat that pizza.

data X =
  X
    { field1 :: Int -- ^ Field1 is the first field.
    , field11 :: Char
      -- ^ This field comment is on its own line.
    , field2 :: Int -- ^ Field2 is the second field.
    , field3 :: Char -- ^ This is a long comment which starts next to
      -- the field but continues onto the next line, it aligns exactly
      -- with the field name.
    , field4 :: Char
      -- ^ This is a long comment which starts on the following line
      -- from from the field, lines continue at the sme column.
    }

Comments around regular declarations

-- This is some random comment.
-- | Main entry point.
main = putStrLn "Hello, World!"
-- This is another random comment.

Multi-line comments

bob {- after bob -}
 =
  foo {- next to foo -}
  {- line after foo -}
    (bar
       foo {- next to bar foo -}
       bar {- next to bar -}
     ) {- next to the end paren of (bar) -}
    {- line after (bar) -}
    mu {- next to mu -}
    {- line after mu -}
    {- another line after mu -}
    zot {- next to zot -}
    {- line after zot -}
    (case casey {- after casey -}
           of
       Just {- after Just -}
        -> do
         justice {- after justice -}
          *
           foo
             (blah * blah + z + 2 / 4 + a - {- before a line break -}
              2 * {- inside this mess -}
              z /
              2 /
              2 /
              aooooo /
              aaaaa {- bob comment -}
              ) +
           (sdfsdfsd fsdfsdf) {- blah comment -}
         putStrLn "")
    [1, 2, 3]
    [ 1 {- foo -}
    , ( 2 {- bar -}
      , 2.5 {- mu -}
       )
    , 3
    ]

foo = 1 {- after foo -}

Multi-line comments with multi-line contents

{- | This is some random comment.
Here is more docs and such.
Etc.
-}
main = putStrLn "Hello, World!"
{- This is another random comment. -}

MINIMAL pragma

Monad example

class A where
  {-# MINIMAL return, ((>>=) | (join, fmap)) #-}

Very long names #310

class A where
  {-# MINIMAL averylongnamewithnoparticularmeaning
            | ananotherverylongnamewithnomoremeaning #-}

Behaviour checks

Unicode

α = γ * "ω"
-- υ

Empty module

Trailing newline is preserved

module X where

foo = 123

Complex input

A complex, slow-to-print decl

quasiQuotes =
  [ ( ''[]
    , \(typeVariable:_) _automaticPrinter ->
        (let presentVar = varE (presentVarName typeVariable)
          in lamE
               [varP (presentVarName typeVariable)]
               [|(let typeString = "[" ++ fst $(presentVar) ++ "]"
                   in ( typeString
                      , \xs ->
                          case fst $(presentVar) of
                            "GHC.Types.Char" ->
                              ChoicePresentation
                                "String"
                                [ ( "String"
                                  , StringPresentation
                                      "String"
                                      (concatMap
                                         getCh
                                         (map (snd $(presentVar)) xs)))
                                , ( "List of characters"
                                  , ListPresentation
                                      typeString
                                      (map (snd $(presentVar)) xs))
                                ]
                              where getCh (CharPresentation "GHC.Types.Char" ch) =
                                      ch
                                    getCh (ChoicePresentation _ ((_, CharPresentation _ ch):_)) =
                                      ch
                                    getCh _ = ""
                            _ ->
                              ListPresentation
                                typeString
                                (map (snd $(presentVar)) xs)))|]))
  ]

Random snippet from hindent itself

exp' (App _ op a) = do
  (fits, st) <- fitsOnOneLine (spaced (map pretty (f : args)))
  if fits
    then put st
    else do
      pretty f
      newline
      spaces <- getIndentSpaces
      indented spaces (lined (map pretty args))
  where
    (f, args) = flatten op [a]
    flatten :: Exp NodeInfo -> [Exp NodeInfo] -> (Exp NodeInfo, [Exp NodeInfo])
    flatten (App _ f' a') b = flatten f' (a' : b)
    flatten f' as = (f', as)

Quasi quotes

exp = [name|exp|]

f [qq|pattern|] = ()

C preprocessor

Conditionals (#if)

isDebug :: Bool
#if DEBUG
isDebug = True
#else
isDebug = False
#endif

Macro definitions (#define)

#define STRINGIFY(x) #x
f = STRINGIFY (y)

Escaped newlines

#define LONG_MACRO_DEFINITION \
  data Pair a b = Pair \
    { first :: a \
    , second :: b \
    }
#define SHORT_MACRO_DEFINITION \
  x

Regression tests

jml Adds trailing whitespace when wrapping #221

x = do
  config <- execParser options
  comments <-
    case config of
      Diff False args -> commentsFromDiff args
      Diff True args -> commentsFromDiff ("--cached" : args)
      Files args -> commentsFromFiles args
  mapM_ (putStrLn . Fixme.formatTodo) (concatMap Fixme.getTodos comments)

meditans hindent freezes when trying to format this code #222

c :: forall new.
     ( Settable "pitch" Pitch (Map.AsMap (new Map.:\ "pitch")) new
     , Default (Book' (Map.AsMap (new Map.:\ "pitch")))
     )
  => Book' new
c = set #pitch C (def :: Book' (Map.AsMap (new Map.:\ "pitch")))

foo ::
     ( Foooooooooooooooooooooooooooooooooooooooooo
     , Foooooooooooooooooooooooooooooooooooooooooo
     )
  => A

bitemyapp wonky multiline comment handling #231

module Woo where

hi = "hello"
{-
test comment
-}
-- blah blah
-- blah blah
-- blah blah

cocreature removed from declaration issue #186

-- https://github.com/chrisdone/hindent/issues/186
trans One e n =
  M.singleton
    (Query Unmarked (Mark NonExistent)) -- The goal of this is to fail always
    (emptyImage {notPresent = S.singleton (TransitionResult Two (Just A) n)})

sheyll explicit forall in instances #218

-- https://github.com/chrisdone/hindent/issues/218
instance forall x. C

instance forall x. Show x => C x

tfausak support shebangs #208

#!/usr/bin/env stack
-- stack runghc
main =
 pure ()
-- https://github.com/chrisdone/hindent/issues/208
#!/usr/bin/env stack
-- stack runghc
main = pure ()
-- https://github.com/chrisdone/hindent/issues/208

joe9 preserve newlines between import groups

-- https://github.com/chrisdone/hindent/issues/200
import Data.List
import Data.Maybe

import FooBar
import MyProject

import GHC.Monad

-- blah
import Hello

import CommentAfter -- Comment here shouldn't affect newlines
import HelloWorld

import CommentAfter -- Comment here shouldn't affect newlines

import HelloWorld

-- Comment here shouldn't affect newlines
import CommentAfter

import HelloWorld

Wrapped import list shouldn't add newline

import ATooLongList
       (alpha, beta, gamma, delta, epsilon, zeta, eta, theta)
import B
import ATooLongList (alpha, beta, delta, epsilon, eta, gamma, theta, zeta)
import B

radupopescu deriving keyword not aligned with pipe symbol for type declarations

data Stuffs
  = Things
  | This
  | That
  deriving (Show)

data Simple =
  Simple
  deriving (Show)

sgraf812 top-level pragmas should not add an additional newline #255

-- https://github.com/chrisdone/hindent/issues/255
{-# INLINE f #-}
f :: Int -> Int
f n = n

ivan-timokhin breaks code with type operators #277

-- https://github.com/chrisdone/hindent/issues/277
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}

type m ~> n = ()

class (a :< b) c

ivan-timokhin variables swapped around in constraints #278

-- https://github.com/chrisdone/hindent/issues/278
data Link c1 c2 a c =
  forall b. (c1 a b, c2 b c) =>
            Link (Proxy b)

ttuegel qualified infix sections get mangled #273

-- https://github.com/chrisdone/hindent/issues/273
import qualified Data.Vector as V

main :: IO ()
main = do
  let _ = foldr1 (V.++) [V.empty, V.empty]
  pure ()

-- more corner cases.
xs = V.empty V.++ V.empty

ys = (++) [] []

cons :: V.Vector a -> V.Vector a -> V.Vector a
cons = (V.++)

ivan-timokhin breaks operators type signatures #301

-- https://github.com/chrisdone/hindent/issues/301
(+) :: ()

cdepillabout Long deriving clauses are not reformatted #289

newtype Foo =
  Foo Proxy
  deriving ( Functor
           , Applicative
           , Monad
           , Semigroup
           , Monoid
           , Alternative
           , MonadPlus
           , Foldable
           , Traversable
           )

ivan-timokhin Breaks instances with type operators #342

-- https://github.com/chrisdone/hindent/issues/342
instance Foo (->)

instance Foo (^>)

instance Foo (T.<^)

Indents record constructions and updates #358

foo =
  assert
    sanityCheck
    BomSnapshotAggr
      { snapshot = Just bs
      , previousId = M.bomSnapshotHistoryPreviousId . entityVal <$> bsp
      , nextId = M.bomSnapshotHistoryNextId . entityVal <$> bsn
      , bomEx = bx''
      , orderSubstitutes =
          S.fromList . map OrderSubstituteAggrByCreatedAtAsc $ subs
      , snapshotSubstitute = msub
      }

paraseba Deriving strategies with multiple deriving clauses

-- https://github.com/commercialhaskell/hindent/issues/503
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Foo where

import Data.Typeable
import GHC.Generics

newtype Number a =
  Number a
  deriving (Generic)
  deriving newtype (Show, Eq)
  deriving anyclass (Typeable)

neongreen "{" is lost when formatting "Foo{}" #366

-- https://github.com/chrisdone/hindent/issues/366
foo = Nothing {}

jparoz Trailing space in list comprehension #357

-- https://github.com/chrisdone/hindent/issues/357
foo =
  [ (x, y)
  | x <- [1 .. 10]
  , y <- [11 .. 20]
  , even x
  , even x
  , even x
  , even x
  , even x
  , odd y
  ]

ttuegel Record formatting applied to expressions with RecordWildCards #274

-- https://github.com/chrisdone/hindent/issues/274
foo (Bar {..}) = Bar {..}

RecursiveDo rec and mdo keyword #328

rec = undefined

mdo = undefined

sophie-h Record syntax change in 5.2.2 #393

-- https://github.com/commercialhaskell/hindent/issues/393
data X
  = X
      { x :: Int
      }
  | X'

data X =
  X
    { x :: Int
    , x' :: Int
    }

data X
  = X
      { x :: Int
      , x' :: Int
      }
  | X'

k-bx Infix data constructor gets reformatted into a parse error #328

-- https://github.com/commercialhaskell/hindent/issues/328
data Expect =
  String :--> String
  deriving (Show)

tfausak Class constraints cause too many newlines #244

-- https://github.com/commercialhaskell/hindent/issues/244
x :: Num a => a
x = undefined

-- instance
instance Num a => C a

-- long instance
instance Nuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum a =>
         C a where
  f = undefined

expipiplus1 Always break before :: on overlong signatures #390

-- https://github.com/commercialhaskell/hindent/issues/390
fun :: Is => Short
fun = undefined

someFunctionSignature ::
     Wiiiiiiiiiiiiiiiiith
  -> Enough
  -> (Arguments -> To ())
  -> Overflow (The Line Limit)

duog Long Type Constraint Synonyms are not reformatted #290

-- https://github.com/commercialhaskell/hindent/issues/290
type MyContext m
   = ( MonadState Int m
     , MonadReader Int m
     , MonadError Text m
     , MonadMask m
     , Monoid m
     , Functor m)

ocharles Type application differs from function application (leading to long lines) #359

-- https://github.com/commercialhaskell/hindent/issues/359
thing ::
     ( ResB.BomEx
     , Maybe [( Entity BomSnapshot
              , ( [ResBS.OrderSubstituteAggr]
                , ( Maybe (Entity BomSnapshotHistory)
                  , Maybe (Entity BomSnapshotHistory))))])
  -> [(ResB.BomEx, Maybe ResBS.BomSnapshotAggr)]

NorfairKing Do as left-hand side of an infix operation #296

-- https://github.com/commercialhaskell/hindent/issues/296
block =
  do ds <- inBraces $ inWhiteSpace declarations
     return $ Block ds
     <?> "block"

NorfairKing Hindent linebreaks after very short names if the total line length goes over 80 #405

-- https://github.com/commercialhaskell/hindent/issues/405
t =
  f "this is a very loooooooooooooooooooooooooooong string that goes over the line length"
    argx
    argy
    argz

t =
  function
    "this is a very loooooooooooooooooooooooooooong string that goes over the line length"
    argx
    argy
    argz

ivan-timokhin No linebreaks for long functional dependency declarations #323

-- https://github.com/commercialhaskell/hindent/issues/323
class Foo a b | a -> b where
  f :: a -> b

class Foo a b c d e f
  | a b c d e -> f
  , a b c d f -> e
  , a b c e f -> d
  , a b d e f -> c
  , a c d e f -> b
  , b c d e f -> a
  where
  foo :: a -> b -> c -> d -> e -> f

utdemir Hindent breaks TH name captures of operators #412

-- https://github.com/commercialhaskell/hindent/issues/412
data T =
  (-)

q = '(-)

data (-)

q = ''(-)

utdemir Hindent can not parse empty case statements #414

-- https://github.com/commercialhaskell/hindent/issues/414
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE LambdaCase #-}

f1 = case () of {}

f2 = \case {}

TimoFreiberg INLINE (and other) pragmas for operators are reformatted without parens #415

-- https://github.com/commercialhaskell/hindent/issues/415
{-# NOINLINE (<>) #-}

NorfairKing Hindent breaks servant API's #417

-- https://github.com/commercialhaskell/hindent/issues/417
type API = api1 :<|> api2

andersk Cannot parse @: operator #421

-- https://github.com/commercialhaskell/hindent/issues/421
a @: b = a + b

main = print (2 @: 2)

andersk Corrupts parenthesized type operators #422

-- https://github.com/commercialhaskell/hindent/issues/422
data T a =
  a :@ a

test = (:@)

NorfairKing Infix constructor pattern is broken #424

-- https://github.com/commercialhaskell/hindent/issues/424
from $ \(author `InnerJoin` post) -> pure ()

NorfairKing Hindent can no longer parse type applications code #426

-- https://github.com/commercialhaskell/hindent/issues/426
{-# LANGUAGE TypeApplications #-}

f :: Num a => a
f = id

x = f @Int 12

michalrus Multiline GHC.TypeLits.Symbols are being broken #451

-- https://github.com/commercialhaskell/hindent/issues/451
import GHC.TypeLits (Symbol)

data X (sym :: Symbol)
  deriving (Typeable)

type Y = X "abc\n\n\ndef"

DavidEichmann Existential Quantification reordered #443

-- https://github.com/commercialhaskell/hindent/issues/443
{-# LANGUAGE ExistentialQuantification #-}

data D =
  forall a b c. D a b c

sophie-h Regression: Breaks basic type class code by inserting "|" #459

-- https://github.com/commercialhaskell/hindent/issues/459
class Class1 a =>
      Class2 a
  where
  f :: a -> Int

class (Eq a, Show a) =>
      Num a
  where
  (+), (-), (*) :: a -> a -> a
  negate :: a -> a
  abs, signum :: a -> a
  fromInteger :: Integer -> a

michalrus let … in … inside of do breaks compilation #467

-- https://github.com/commercialhaskell/hindent/issues/467
main :: IO ()
main = do
  let x = 5
   in when (x > 0) (return ())

sophie-h Breaking valid top-level template haskell #473

-- https://github.com/commercialhaskell/hindent/issues/473
template $
  haskell
    [ ''SomeVeryLongName
    , ''AnotherLongNameEvenLongToBreakTheLine
    , ''LastLongNameInList
    ]

schroffl Hindent produces invalid Syntax from FFI exports #479

-- https://github.com/commercialhaskell/hindent/issues/479
foreign export ccall "test" test :: IO ()

foreign import ccall "test" test :: IO ()

foreign import ccall safe "test" test :: IO ()

foreign import ccall unsafe "test" test :: IO ()

ptek Reformatting of the {-# OVERLAPPING #-} pragma #386

-- https://github.com/commercialhaskell/hindent/issues/386
instance {-# OVERLAPPING #-} Arbitrary (Set Int) where
  arbitrary = undefined

cdsmith Quotes are dropped from package imports #480

-- https://github.com/commercialhaskell/hindent/issues/480
{-# LANGUAGE PackageImports #-}

import qualified "base" Prelude as P

alexwl Hindent breaks associated type families annotated with injectivity information #528

-- https://github.com/commercialhaskell/hindent/issues/528
class C a where
  type F a = b | b -> a

sophie-h Fails to create required indentation for infix #238

-- https://github.com/commercialhaskell/hindent/issues/238
{-# LANGUAGE ScopedTypeVariables #-}

import Control.Exception

x :: IO Int
x =
  do putStrLn "ok"
     error "ok"
     `catch` (\(_ :: IOException) -> pure 1) `catch`
  (\(_ :: ErrorCall) -> pure 2)

lippirk Comments on functions in where clause not quite right #540

-- https://github.com/chrisdone/hindent/issues/540
topLevelFunc1 = f
  where
    -- comment on func in where clause
    -- stays in the where clause
    f = undefined

topLevelFunc2 = f . g
  where
    {- multi
       line
       comment -}
    f = undefined
    -- single line comment
    g = undefined