diff options
Diffstat (limited to 'lib/Language/Haskell/Stylish/Config.hs')
-rw-r--r-- | lib/Language/Haskell/Stylish/Config.hs | 68 |
1 files changed, 54 insertions, 14 deletions
diff --git a/lib/Language/Haskell/Stylish/Config.hs b/lib/Language/Haskell/Stylish/Config.hs index 8f43131..475a5e3 100644 --- a/lib/Language/Haskell/Stylish/Config.hs +++ b/lib/Language/Haskell/Stylish/Config.hs @@ -16,24 +16,29 @@ import Data.Aeson (FromJSON (..) import qualified Data.Aeson as A import qualified Data.Aeson.Types as A import qualified Data.ByteString as B +import Data.ByteString.Lazy (fromStrict) +import Data.Char (toLower) import qualified Data.FileEmbed as FileEmbed import Data.List (intercalate, nub) import Data.Map (Map) import qualified Data.Map as M import Data.Maybe (fromMaybe) -import Data.Yaml (decodeEither', - prettyPrintParseException) +import qualified Data.Text as T +import Data.YAML (prettyPosWithSource) +import Data.YAML.Aeson (decode1Strict) import System.Directory import System.FilePath ((</>)) import qualified System.IO as IO (Newline (..), nativeNewline) +import Text.Read (readMaybe) -------------------------------------------------------------------------------- import qualified Language.Haskell.Stylish.Config.Cabal as Cabal import Language.Haskell.Stylish.Config.Internal import Language.Haskell.Stylish.Step +import qualified Language.Haskell.Stylish.Step.Data as Data import qualified Language.Haskell.Stylish.Step.Imports as Imports import qualified Language.Haskell.Stylish.Step.LanguagePragmas as LanguagePragmas import qualified Language.Haskell.Stylish.Step.SimpleAlign as SimpleAlign @@ -51,7 +56,7 @@ type Extensions = [String] -------------------------------------------------------------------------------- data Config = Config { configSteps :: [Step] - , configColumns :: Int + , configColumns :: Maybe Int , configLanguageExtensions :: [String] , configNewline :: IO.Newline , configCabal :: Bool @@ -80,12 +85,10 @@ configFilePath verbose Nothing = do current <- getCurrentDirectory configPath <- getXdgDirectory XdgConfig "stylish-haskell" home <- getHomeDirectory - mbConfig <- search verbose $ + search verbose $ [d </> configFileName | d <- ancestors current] ++ [configPath </> "config.yaml", home </> configFileName] - return mbConfig - search :: Verbose -> [FilePath] -> IO (Maybe FilePath) search _ [] = return Nothing search verbose (f : fs) = do @@ -100,9 +103,8 @@ loadConfig verbose userSpecified = do mbFp <- configFilePath verbose userSpecified verbose $ "Loading configuration at " ++ fromMaybe "<embedded>" mbFp bytes <- maybe (return defaultConfigBytes) B.readFile mbFp - case decodeEither' bytes of - Left err -> error $ - "Language.Haskell.Stylish.Config.loadConfig: " ++ prettyPrintParseException err + case decode1Strict bytes of + Left (pos, err) -> error $ prettyPosWithSource pos (fromStrict bytes) ("Language.Haskell.Stylish.Config.loadConfig: " ++ err) Right config -> do cabalLanguageExtensions <- if configCabal config then map show <$> Cabal.findLanguageExtensions verbose @@ -120,7 +122,7 @@ parseConfig (A.Object o) = do -- First load the config without the actual steps config <- Config <$> pure [] - <*> (o A..:? "columns" A..!= 80) + <*> (o A..:! "columns" A..!= Just 80) <*> (o A..:? "language_extensions" A..!= []) <*> (o A..:? "newline" >>= parseEnum newlines IO.nativeNewline) <*> (o A..:? "cabal" A..!= True) @@ -142,6 +144,7 @@ parseConfig _ = mzero catalog :: Map String (Config -> A.Object -> A.Parser Step) catalog = M.fromList [ ("imports", parseImports) + , ("records", parseRecords) , ("language_pragmas", parseLanguagePragmas) , ("simple_align", parseSimpleAlign) , ("squash", parseSquash) @@ -181,6 +184,28 @@ parseSimpleAlign c o = SimpleAlign.step where withDef f k = fromMaybe (f SimpleAlign.defaultConfig) <$> (o A..:? k) +-------------------------------------------------------------------------------- +parseRecords :: Config -> A.Object -> A.Parser Step +parseRecords _ o = Data.step + <$> (Data.Config + <$> (o A..: "equals" >>= parseIndent) + <*> (o A..: "first_field" >>= parseIndent) + <*> (o A..: "field_comment") + <*> (o A..: "deriving")) + + +parseIndent :: A.Value -> A.Parser Data.Indent +parseIndent = A.withText "Indent" $ \t -> + if t == "same_line" + then return Data.SameLine + else + if "indent " `T.isPrefixOf` t + then + case readMaybe (T.unpack $ T.drop 7 t) of + Just n -> return $ Data.Indent n + Nothing -> fail $ "Indent: not a number" <> T.unpack (T.drop 7 t) + else fail $ "can't parse indent setting: " <> T.unpack t + -------------------------------------------------------------------------------- parseSquash :: Config -> A.Object -> A.Parser Step @@ -200,9 +225,9 @@ parseImports config o = Imports.step -- Note that padding has to be at least 1. Default is 4. <*> (o A..:? "empty_list_align" >>= parseEnum emptyListAligns (def Imports.emptyListAlign)) - <*> o A..:? "list_padding" A..!= (def Imports.listPadding) - <*> o A..:? "separate_lists" A..!= (def Imports.separateLists) - <*> o A..:? "space_surround" A..!= (def Imports.spaceSurround)) + <*> o A..:? "list_padding" A..!= def Imports.listPadding + <*> o A..:? "separate_lists" A..!= def Imports.separateLists + <*> o A..:? "space_surround" A..!= def Imports.spaceSurround) where def f = f Imports.defaultOptions @@ -237,8 +262,9 @@ parseLanguagePragmas :: Config -> A.Object -> A.Parser Step parseLanguagePragmas config o = LanguagePragmas.step <$> pure (configColumns config) <*> (o A..:? "style" >>= parseEnum styles LanguagePragmas.Vertical) - <*> o A..:? "align" A..!= True + <*> o A..:? "align" A..!= True <*> o A..:? "remove_redundant" A..!= True + <*> mkLanguage o where styles = [ ("vertical", LanguagePragmas.Vertical) @@ -248,6 +274,19 @@ parseLanguagePragmas config o = LanguagePragmas.step -------------------------------------------------------------------------------- +-- | Utilities for validating language prefixes +mkLanguage :: A.Object -> A.Parser String +mkLanguage o = do + lang <- o A..:? "language_prefix" + maybe (pure "LANGUAGE") validate lang + where + validate :: String -> A.Parser String + validate s + | fmap toLower s == "language" = pure s + | otherwise = fail "please provide a valid language prefix" + + +-------------------------------------------------------------------------------- parseTabs :: Config -> A.Object -> A.Parser Step parseTabs _ o = Tabs.step <$> o A..:? "spaces" A..!= 8 @@ -262,3 +301,4 @@ parseTrailingWhitespace _ _ = return TrailingWhitespace.step parseUnicodeSyntax :: Config -> A.Object -> A.Parser Step parseUnicodeSyntax _ o = UnicodeSyntax.step <$> o A..:? "add_language_pragma" A..!= True + <*> mkLanguage o |