packages feed

mida-1.0.0: src/Mida/Configuration.hs

--
-- Parse YAML configuration.
--
-- Copyright © 2014–2016 Mark Karpov
--
-- MIDA is free software: you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- MIDA is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-- details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program. If not, see <http://www.gnu.org/licenses/>.

{-# LANGUAGE TemplateHaskell #-}

module Mida.Configuration
  ( MidaConfig (..)
  , parseMidaConfig
  , def )
where

import Control.Monad.IO.Class
import Data.Aeson (withObject)
import Data.Default
import Data.Yaml
import Numeric.Natural
import Path

-- | MIDA configuration.

data MidaConfig = MidaConfig
  { configPrevLen :: Natural       -- ^ Length of preview principles
  , configSrcFile :: Path Rel File -- ^ Name of current source file
  , configProg    :: Natural       -- ^ Program to use for preview
  , configTempo   :: Natural       -- ^ Tempo to use for preview
  , configPrompt  :: String        -- ^ REPL prompt
  , configVerbose :: Bool          -- ^ Verbose mode?
  , configPrvCmd  :: String        -- ^ Command to use for preview
  , configProgOp  :: String        -- ^ Option to set program for preview
  , configTempoOp :: String        -- ^ Option to set tempo for preview
  } deriving (Eq, Show)

instance Default MidaConfig where
  def = MidaConfig
    { configPrevLen = 18
    , configSrcFile = $(mkRelFile "foo.da")
    , configProg    = 0
    , configTempo   = 120
    , configPrompt  = "> "
    , configVerbose = True
    , configPrvCmd  = "timidity"
    , configProgOp  = "--force-program"
    , configTempoOp = "--adjust-tempo"
    }

instance FromJSON MidaConfig where
  parseJSON = withObject "MIDA Configuration" $ \o -> do
    let ω f g n = do
          mval <- o .:? n
          case mval of
            Nothing -> return (f def)
            Just val -> g val
        ξ x = case parseRelFile x of
                Nothing -> fail $ "cannot parse relative path: " ++ show x
                Just path -> return path
        τ :: Int -> Parser Natural
        τ x = if x >= 0
                then return (fromIntegral x)
                else fail $ "the value must be positive: " ++ show x
    configPrevLen <- ω configPrevLen τ "prevlen"
    configSrcFile <- ω configSrcFile ξ "src"
    configProg    <- ω configProg    τ "prog"
    configTempo   <- ω configTempo   τ "tempo"
    configPrompt  <- ω configPrompt  return "prompt"
    configVerbose <- ω configVerbose return "verbose"
    configPrvCmd  <- ω configPrvCmd  return "prvcmd"
    configProgOp  <- ω configProgOp  return "progop"
    configTempoOp <- ω configTempoOp return "tempop"
    return MidaConfig {..}

parseMidaConfig :: MonadIO m => Path b File -> m (Either String MidaConfig)
parseMidaConfig path = liftIO $
  either (Left . prettyPrintParseException) Right
    <$> decodeFileEither (toFilePath path)