coformat-0.3.0.0: src/Clang/Format/Formatter.hs
{-# LANGUAGE GADTs, TypeApplications, DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards, QuasiQuotes, OverloadedStrings #-}
module Clang.Format.Formatter(clangFormatter) where
import qualified Control.Monad.Except.CoHas as EC
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as LBS
import qualified Data.HashMap.Strict as HM
import Control.Lens
import Control.Monad.Except
import Data.Aeson.Lens
import Data.Bifunctor
import Data.List
import Data.String.Interpolate
import Clang.Format.DescrParser
import Clang.Format.StyOpts
import Clang.Format.YamlConversions
import Language.Coformat.Descr
import Language.Coformat.Descr.Operations
import Language.Coformat.Formatter
import Language.Coformat.Util
clangFormatter :: Formatter
clangFormatter = Formatter { .. }
where
formatterInfo = FormatterInfo { .. }
where
execName = "clang-format"
formatterOpts = OptsFromFile "data/ClangFormatStyleOptions-9.html" parseOptsDescription
hardcodedOpts = [ ConfigItem { name = ["Language"], value = CTEnum ["Cpp"] "Cpp" }
, ConfigItem { name = ["BreakBeforeBraces"], value = CTEnum ["Custom"] "Custom" }
, ConfigItem { name = ["DisableFormat"], value = CTBool False }
, ConfigItem { name = ["SortIncludes"], value = CTBool False }
]
defaultStyleOpts sty supported allFixedOpts = OptsFromCmd (CmdArgs args) parser
where
args = [ "--style=" <> formattedBaseSty, "--dump-config" ]
parser = convert (show @FillError) . fillConfigItems supported
formattedBaseSty = formatStyArg $ StyOpts { basedOnStyle = sty, additionalOpts = allFixedOpts }
formatFile baseSty opts path = CmdArgs { args = [ "--style=" <> formattedBaseSty, BS.pack path ] }
where
formattedBaseSty = formatStyArg $ StyOpts { basedOnStyle = baseSty, additionalOpts = opts }
serializeOptions baseSty opts = formatClangFormat StyOpts { basedOnStyle = baseSty, additionalOpts = opts }
parseResumeObject = convert (show @FillError) . preprocessYaml PartialConfig
parseResumeOptions knownOpts resumeObj = do
baseStyle <- EC.liftMaybe ("Unable to find `BasedOnStyle` key in the resume file" :: String)
$ HM.lookup "BasedOnStyle" resumeObj ^? _Just . _String
opts <- convert (show @FillError) $ collectConfigItems knownOpts resumeObj
pure (baseStyle, opts)
liftEither' :: (MonadError String m, Show e) => String -> Either e a -> m a
liftEither' context = liftEither . first ((context <>) . show)
parseOptsDescription :: LBS.ByteString -> Either String (OptsDescription 'Supported)
parseOptsDescription contents = do
parseResult <- liftEither' "Unable to parse the file: " $ parseDescr contents
let supportedOptions = filterParsedItems parseResult
baseStyles <- case find ((== bosKey) . name) supportedOptions of
Nothing -> throwError "No `BasedOnStyle` option"
Just stys -> pure stys
let varyingOptions = filter ((/= bosKey) . name) supportedOptions
case value baseStyles of
CTEnum { .. } -> pure $ OptsDescription { baseStyles = variants, knownOpts = varyingOptions }
_ -> throwError [i|Unknown type for the `BaseStyles` option: #{value baseStyles}|]
where
bosKey = ["BasedOnStyle"]