content: {-# LANGUAGE NamedFieldPuns #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Floskell.Styles ( Style(..), styles ) where
  
  import qualified Data.Map        as Map
  import qualified Data.Set        as Set
  import           Data.Text       ( Text )
  
  import           Floskell.Config
  
  -- | A printer style.
  data Style =
      Style { styleName        :: !Text   -- ^ Name of the style, used in the commandline interface.
            , styleAuthor      :: !Text   -- ^ Author of the style definition.
            , styleDescription :: !Text   -- ^ Description of the style.
            , styleConfig      :: !Config -- ^ Style definition.
            }
  
  chrisDoneCfg :: Config
  chrisDoneCfg =
      defaultConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions }
    where
      cfgIndent =
          IndentConfig { cfgIndentOnside         = 2
                       , cfgIndentDeriving       = 2
                       , cfgIndentWhere          = 2
                       , cfgIndentApp            = Align
                       , cfgIndentCase           = IndentBy 2
                       , cfgIndentClass          = IndentBy 2
                       , cfgIndentDo             = Align
                       , cfgIndentIf             = IndentBy 3
                       , cfgIndentLet            = Align
                       , cfgIndentLetBinds       = Align
                       , cfgIndentLetIn          = Align
                       , cfgIndentMultiIf        = IndentBy 2
                       , cfgIndentTypesig        = Align
                       , cfgIndentWhereBinds     = Align
                       , cfgIndentExportSpecList = IndentBy 2
                       , cfgIndentImportSpecList = AlignOrIndentBy 7
                       }
  
      cfgLayout = LayoutConfig { cfgLayoutApp            = TryOneline
                               , cfgLayoutConDecls       = Vertical
                               , cfgLayoutDeclaration    = TryOneline
                               , cfgLayoutExportSpecList = TryOneline
                               , cfgLayoutIf             = Vertical
                               , cfgLayoutImportSpecList = Flex
                               , cfgLayoutInfixApp       = TryOneline
                               , cfgLayoutLet            = Vertical
                               , cfgLayoutListComp       = Flex
                               , cfgLayoutRecord         = Vertical
                               , cfgLayoutType           = TryOneline
                               }
  
      cfgOp =
          OpConfig ConfigMap { cfgMapDefault   = Whitespace WsBoth WsBefore False
                             , cfgMapOverrides = Map.fromList opWsOverrides
                             }
  
      opWsOverrides =
          [ (ConfigMapKey (Just ",") Nothing, Whitespace WsNone WsBefore False)
          , ( ConfigMapKey (Just "record") Nothing
            , Whitespace WsAfter WsNone False
            )
          , ( ConfigMapKey (Just ".") (Just Type)
            , Whitespace WsAfter WsAfter False
            )
          , (ConfigMapKey (Just "=") Nothing, Whitespace WsBoth WsAfter False)
          , (ConfigMapKey (Just "<-") Nothing, Whitespace WsBoth WsAfter False)
          , (ConfigMapKey (Just ":") Nothing, Whitespace WsNone WsBefore False)
          ]
  
      cfgGroup =
          GroupConfig ConfigMap { cfgMapDefault   =
                                      Whitespace WsNone WsNone False
                                , cfgMapOverrides = Map.fromList groupWsOverrides
                                }
  
      groupWsOverrides = []
  
      cfgOptions = OptionConfig { cfgOptionSortPragmas            = False
                                , cfgOptionSplitLanguagePragmas   = False
                                , cfgOptionSortImports            = NoImportSort
                                , cfgOptionSortImportLists        = False
                                , cfgOptionAlignSumTypeDecl       = True
                                , cfgOptionFlexibleOneline        = False
                                , cfgOptionPreserveVerticalSpace  = False
                                , cfgOptionDeclNoBlankLines       = Set.empty
                                , cfgOptionAlignLetBindsAndInExpr = False
                                }
  
  cramerCfg :: Config
  cramerCfg = defaultConfig { cfgAlign
                            , cfgIndent
                            , cfgLayout
                            , cfgOp
                            , cfgGroup
                            , cfgOptions
                            }
    where
      cfgAlign = AlignConfig { cfgAlignLimits       = (10, 25)
                             , cfgAlignCase         = False
                             , cfgAlignClass        = False
                             , cfgAlignImportModule = True
                             , cfgAlignImportSpec   = True
                             , cfgAlignLetBinds     = False
                             , cfgAlignMatches      = False
                             , cfgAlignRecordFields = True
                             , cfgAlignWhere        = False
                             }
  
      cfgIndent =
          IndentConfig { cfgIndentOnside         = 4
                       , cfgIndentDeriving       = 4
                       , cfgIndentWhere          = 2
                       , cfgIndentApp            = Align
                       , cfgIndentCase           = IndentBy 4
                       , cfgIndentClass          = IndentBy 4
                       , cfgIndentDo             = IndentBy 4
                       , cfgIndentIf             = Align
                       , cfgIndentLet            = Align
                       , cfgIndentLetBinds       = Align
                       , cfgIndentLetIn          = IndentBy 4
                       , cfgIndentMultiIf        = IndentBy 4
                       , cfgIndentTypesig        = Align
                       , cfgIndentWhereBinds     = IndentBy 2
                       , cfgIndentExportSpecList = IndentBy 4
                       , cfgIndentImportSpecList = AlignOrIndentBy 17
                       }
  
      cfgLayout = LayoutConfig { cfgLayoutApp            = TryOneline
                               , cfgLayoutConDecls       = TryOneline
                               , cfgLayoutDeclaration    = Flex
                               , cfgLayoutExportSpecList = TryOneline
                               , cfgLayoutIf             = TryOneline
                               , cfgLayoutImportSpecList = Flex
                               , cfgLayoutInfixApp       = Flex
                               , cfgLayoutLet            = TryOneline
                               , cfgLayoutListComp       = TryOneline
                               , cfgLayoutRecord         = TryOneline
                               , cfgLayoutType           = TryOneline
                               }
  
      cfgOp =
          OpConfig ConfigMap { cfgMapDefault   = Whitespace WsBoth WsBefore False
                             , cfgMapOverrides = Map.fromList opWsOverrides
                             }
  
      opWsOverrides =
          [ (ConfigMapKey (Just ",") Nothing, Whitespace WsAfter WsBefore False)
          , ( ConfigMapKey (Just "record") Nothing
            , Whitespace WsAfter WsNone False
            )
          , ( ConfigMapKey (Just ".") (Just Type)
            , Whitespace WsAfter WsAfter False
            )
          , (ConfigMapKey (Just "=") Nothing, Whitespace WsBoth WsAfter False)
          , (ConfigMapKey (Just "$") Nothing, Whitespace WsBoth WsAfter False)
          , (ConfigMapKey (Just "@") Nothing, Whitespace WsNone WsNone False)
          , ( ConfigMapKey (Just "->") (Just Expression)
            , Whitespace WsBoth WsAfter False
            )
          , ( ConfigMapKey (Just "record") (Just Pattern)
            , Whitespace WsNone WsNone False
            )
          ]
  
      cfgGroup =
          GroupConfig ConfigMap { cfgMapDefault   =
                                      Whitespace WsBoth WsAfter False
                                , cfgMapOverrides = Map.fromList groupWsOverrides
                                }
  
      groupWsOverrides =
          [ (ConfigMapKey Nothing (Just Type), Whitespace WsNone WsAfter False)
          , ( ConfigMapKey Nothing (Just Pattern)
            , Whitespace WsNone WsAfter False
            )
          , (ConfigMapKey (Just "$(") Nothing, Whitespace WsNone WsNone False)
          , (ConfigMapKey (Just "[|") Nothing, Whitespace WsNone WsNone False)
          , (ConfigMapKey (Just "[d|") Nothing, Whitespace WsNone WsNone False)
          , (ConfigMapKey (Just "[p|") Nothing, Whitespace WsNone WsNone False)
          , (ConfigMapKey (Just "[t|") Nothing, Whitespace WsNone WsNone False)
          , (ConfigMapKey (Just "(") Nothing, Whitespace WsNone WsAfter False)
          , ( ConfigMapKey (Just "(") (Just Other)
            , Whitespace WsBoth WsAfter False
            )
          , ( ConfigMapKey (Just "[") (Just Pattern)
            , Whitespace WsBoth WsAfter False
            )
          , (ConfigMapKey (Just "[") (Just Type), Whitespace WsNone WsNone False)
          ]
  
      cfgOptions =
          OptionConfig { cfgOptionSortPragmas            = True
                       , cfgOptionSplitLanguagePragmas   = True
                       , cfgOptionSortImports            = SortImportsByPrefix
                       , cfgOptionSortImportLists        = True
                       , cfgOptionAlignSumTypeDecl       = False
                       , cfgOptionFlexibleOneline        = False
                       , cfgOptionPreserveVerticalSpace  = True
                       , cfgOptionDeclNoBlankLines       = Set.empty
                       , cfgOptionAlignLetBindsAndInExpr = False
                       }
  
  gibianskyCfg :: Config
  gibianskyCfg = defaultConfig { cfgAlign
                               , cfgIndent
                               , cfgLayout
                               , cfgOp
                               , cfgGroup
                               , cfgOptions
                               }
    where
      cfgAlign = AlignConfig { cfgAlignLimits       = (10, 25)
                             , cfgAlignCase         = True
                             , cfgAlignClass        = False
                             , cfgAlignImportModule = True
                             , cfgAlignImportSpec   = False
                             , cfgAlignLetBinds     = False
                             , cfgAlignMatches      = False
                             , cfgAlignRecordFields = False
                             , cfgAlignWhere        = False
                             }
  
      cfgIndent =
          IndentConfig { cfgIndentOnside         = 2
                       , cfgIndentDeriving       = 2
                       , cfgIndentWhere          = 2
                       , cfgIndentApp            = IndentBy 2
                       , cfgIndentCase           = IndentBy 2
                       , cfgIndentClass          = IndentBy 2
                       , cfgIndentDo             = IndentBy 2
                       , cfgIndentIf             = Align
                       , cfgIndentLet            = Align
                       , cfgIndentLetBinds       = Align
                       , cfgIndentLetIn          = Align
                       , cfgIndentMultiIf        = IndentBy 2
                       , cfgIndentTypesig        = Align
                       , cfgIndentWhereBinds     = IndentBy 2
                       , cfgIndentExportSpecList = IndentBy 4
                       , cfgIndentImportSpecList = Align
                       }
  
      cfgLayout = LayoutConfig { cfgLayoutApp            = TryOneline
                               , cfgLayoutConDecls       = Vertical
                               , cfgLayoutDeclaration    = Flex
                               , cfgLayoutExportSpecList = TryOneline
                               , cfgLayoutIf             = Vertical
                               , cfgLayoutImportSpecList = Flex
                               , cfgLayoutInfixApp       = TryOneline
                               , cfgLayoutLet            = Vertical
                               , cfgLayoutListComp       = TryOneline
                               , cfgLayoutRecord         = TryOneline
                               , cfgLayoutType           = TryOneline
                               }
  
      cfgOp =
          OpConfig ConfigMap { cfgMapDefault   = Whitespace WsBoth WsBefore False
                             , cfgMapOverrides = Map.fromList opWsOverrides
                             }
  
      opWsOverrides =
          [ (ConfigMapKey (Just ",") Nothing, Whitespace WsAfter WsBefore False)
          , ( ConfigMapKey (Just "record") Nothing
            , Whitespace WsAfter WsNone False
            )
          , ( ConfigMapKey (Just ".") (Just Type)
            , Whitespace WsAfter WsAfter False
            )
          , (ConfigMapKey (Just "=") Nothing, Whitespace WsBoth WsAfter False)
          , (ConfigMapKey (Just ":") Nothing, Whitespace WsNone WsBefore False)
          ]
  
      cfgGroup =
          GroupConfig ConfigMap { cfgMapDefault   =
                                      Whitespace WsNone WsNone False
                                , cfgMapOverrides = Map.fromList groupWsOverrides
                                }
  
      groupWsOverrides =
          [ (ConfigMapKey (Just "{") Nothing, Whitespace WsBoth WsAfter False) ]
  
      cfgOptions = OptionConfig { cfgOptionSortPragmas            = False
                                , cfgOptionSplitLanguagePragmas   = False
                                , cfgOptionSortImports            = NoImportSort
                                , cfgOptionSortImportLists        = False
                                , cfgOptionAlignSumTypeDecl       = False
                                , cfgOptionFlexibleOneline        = False
                                , cfgOptionPreserveVerticalSpace  = False
                                , cfgOptionDeclNoBlankLines       = Set.empty
                                , cfgOptionAlignLetBindsAndInExpr = False
                                }
  
  johanTibellCfg :: Config
  johanTibellCfg =
      defaultConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions }
    where
      cfgIndent =
          IndentConfig { cfgIndentOnside         = 4
                       , cfgIndentDeriving       = 4
                       , cfgIndentWhere          = 2
                       , cfgIndentApp            = IndentBy 4
                       , cfgIndentCase           = IndentBy 4
                       , cfgIndentClass          = IndentBy 4
                       , cfgIndentDo             = IndentBy 4
                       , cfgIndentIf             = IndentBy 4
                       , cfgIndentLet            = Align
                       , cfgIndentLetBinds       = Align
                       , cfgIndentLetIn          = Align
                       , cfgIndentMultiIf        = IndentBy 2
                       , cfgIndentTypesig        = Align
                       , cfgIndentWhereBinds     = IndentBy 2
                       , cfgIndentExportSpecList = IndentBy 2
                       , cfgIndentImportSpecList = AlignOrIndentBy 7
                       }
  
      cfgLayout = LayoutConfig { cfgLayoutApp            = TryOneline
                               , cfgLayoutConDecls       = Vertical
                               , cfgLayoutDeclaration    = TryOneline
                               , cfgLayoutExportSpecList = TryOneline
                               , cfgLayoutIf             = Vertical
                               , cfgLayoutImportSpecList = Flex
                               , cfgLayoutInfixApp       = TryOneline
                               , cfgLayoutLet            = Vertical
                               , cfgLayoutListComp       = Flex
                               , cfgLayoutRecord         = Vertical
                               , cfgLayoutType           = TryOneline
                               }
  
      cfgOp =
          OpConfig ConfigMap { cfgMapDefault   = Whitespace WsBoth WsBefore False
                             , cfgMapOverrides = Map.fromList opWsOverrides
                             }
  
      opWsOverrides =
          [ (ConfigMapKey (Just ",") Nothing, Whitespace WsAfter WsBefore False)
          , ( ConfigMapKey (Just "record") Nothing
            , Whitespace WsAfter WsAfter True
            )
          , ( ConfigMapKey (Just ".") (Just Type)
            , Whitespace WsAfter WsAfter False
            )
          , (ConfigMapKey (Just "=") Nothing, Whitespace WsBoth WsAfter False)
          , ( ConfigMapKey (Just ":") (Just Pattern)
            , Whitespace WsNone WsBefore False
            )
          , ( ConfigMapKey (Just ",") (Just Pattern)
            , Whitespace WsNone WsBefore False
            )
          , ( ConfigMapKey (Just ",") (Just Other)
            , Whitespace WsNone WsBefore False
            )
          , ( ConfigMapKey (Just "record") (Just Pattern)
            , Whitespace WsAfter WsAfter False
            )
          ]
  
      cfgGroup =
          GroupConfig ConfigMap { cfgMapDefault   =
                                      Whitespace WsNone WsNone False
                                , cfgMapOverrides = Map.fromList groupWsOverrides
                                }
  
      groupWsOverrides =
          [ (ConfigMapKey (Just "{") Nothing, Whitespace WsBoth WsAfter False)
          , ( ConfigMapKey (Just "{") (Just Pattern)
            , Whitespace WsNone WsNone False
            )
          ]
  
      cfgOptions = OptionConfig { cfgOptionSortPragmas            = False
                                , cfgOptionSplitLanguagePragmas   = False
                                , cfgOptionSortImports            = NoImportSort
                                , cfgOptionSortImportLists        = False
                                , cfgOptionAlignSumTypeDecl       = True
                                , cfgOptionFlexibleOneline        = True
                                , cfgOptionPreserveVerticalSpace  = False
                                , cfgOptionDeclNoBlankLines       = Set.empty
                                , cfgOptionAlignLetBindsAndInExpr = False
                                }
  
  -- | Base style definition.
  base :: Style
  base = Style { styleName        = "base"
               , styleAuthor      = "Enno Cramer"
               , styleDescription = "Configurable formatting style"
               , styleConfig      = defaultConfig
               }
  
  chrisDone :: Style
  chrisDone = Style { styleName        = "chris-done"
                    , styleAuthor      = "Chris Done"
                    , styleDescription = "Chris Done's style"
                    , styleConfig      = chrisDoneCfg
                    }
  
  cramer :: Style
  cramer = Style { styleName        = "cramer"
                 , styleAuthor      = "Enno Cramer"
                 , styleDescription = "Enno Cramer's style"
                 , styleConfig      = cramerCfg
                 }
  
  gibiansky :: Style
  gibiansky = Style { styleName        = "gibiansky"
                    , styleAuthor      = "Andrew Gibiansky"
                    , styleDescription = "Andrew Gibiansky's style"
                    , styleConfig      = gibianskyCfg
                    }
  
  johanTibell :: Style
  johanTibell = Style { styleName        = "johan-tibell"
                      , styleAuthor      = "Johan Tibell"
                      , styleDescription = "Johan Tibell's style"
                      , styleConfig      = johanTibellCfg
                      }
  
  -- | Styles list, useful for programmatically choosing.
  styles :: [Style]
  styles = [ base, chrisDone, johanTibell, gibiansky, cramer ]
  