packages feed

qux-0.2.0.0: src/Qux/Commands.hs

{-|
Module      : Qux.Commands

Copyright   : (c) Henry J. Wylde, 2015
License     : BSD3
Maintainer  : public@hjwylde.com
-}

{-# OPTIONS_HADDOCK hide, prune #-}

module Qux.Commands where

import Data.Version (showVersion)

import qualified Language.Qux.Version as Qux

import Options.Applicative
import Options.Applicative.Types

import Prelude hiding (print)

import qualified Qux.Commands.Build     as Build
import qualified Qux.Commands.Check     as Check
import qualified Qux.Commands.Compile   as Compile
import qualified Qux.Commands.Print     as Print
import qualified Qux.Version            as Binary

import System.FilePath

import Text.PrettyPrint (Mode(..))


-- * Optparse for Qux

quxPrefs :: ParserPrefs
quxPrefs = prefs $ columns 100

quxInfo :: ParserInfo Options
quxInfo = info (infoOptions <*> qux) (fullDesc <> noIntersperse)
    where
        infoOptions = helper <*> version <*> numericVersion <*> quxVersion
        version = infoOption ("Version " ++ showVersion Binary.version) $ mconcat [
            long "version", short 'V', hidden,
            help "Show this binary's version"
            ]
        numericVersion = infoOption (showVersion Binary.version) $ mconcat [
            long "numeric-version", hidden,
            help "Show this binary's version (without the prefix)"
            ]
        quxVersion = infoOption ("Qux version " ++ showVersion Qux.version) $ mconcat [
            long "qux-version", hidden,
            help "Show the qux version this binary was compiled with"
            ]

-- * Command

data Options = Options {
    argCommand :: Command
    }

qux :: Parser Options
qux = Options <$> subparser (mconcat [
    command "build"     $ info (helper <*> build)   (fullDesc <> progDesc "Build FILES using composable options"),
    command "check"     $ info (helper <*> check)   (fullDesc <> progDesc "Check FILES for correctness" <> header "Shortcut for `qux build --type-check'"),
    command "compile"   $ info (helper <*> compile) (fullDesc <> progDesc "Compile FILES into the LLVM IR" <> header "Shortcut for `qux build --compile'"),
    command "print"     $ info (helper <*> print)   (fullDesc <> progDesc "Pretty print FILE")
    ])


-- * Subcommands

data Command    = Build     Build.Options
                | Check     Check.Options
                | Compile   Compile.Options
                | Print     Print.Options


-- ** Build

build :: Parser Command
build = fmap Build $ Build.Options
    <$> switch (mconcat [
        long "compile", short 'c',
        help "Enable compilation to LLVM IR"
        ])
    <*> strOption (mconcat [
        long "destination", short 'd', metavar "DIR",
        value ("." ++ [pathSeparator]), showDefault,
        help "Specify the output directory to put the compiled LLVM IR"
        ])
    <*> formatOption (mconcat [
        long "format", short 'f', metavar "FORMAT",
        value Build.Bitcode, showDefault,
        help "Specify the LLVM output format as either `bitcode' or `assembly'"
        ])
    <*> switch (mconcat [
        long "type-check",
        help "Enable type checking"
        ])
    <*> some (strArgument $ mconcat [
        metavar "FILES..."
        ])


-- ** Check

check :: Parser Command
check = Check . Check.Options <$> some (strArgument $ mconcat [
    metavar "FILES..."
    ])


-- ** Compile

compile :: Parser Command
compile = fmap Compile $ Compile.Options
    <$> strOption (mconcat [
        long "destination", short 'd', metavar "DIR",
        value ("." ++ [pathSeparator]), showDefault,
        help "Specify the output directory to put the compiled LLVM IR"
        ])
    <*> formatOption (mconcat [
        long "format", short 'f', metavar "FORMAT",
        value Build.Bitcode, showDefault,
        help "Specify the LLVM output format as either `bitcode' or `assembly'"
        ])
    <*> some (strArgument $ mconcat [
        metavar "FILES..."
    ])


-- ** Print

print :: Parser Command
print = fmap Print $ Print.Options
    <$> option auto (mconcat [
        long "line-length", short 'l', metavar "LENGTH",
        value 100, showDefault,
        help "Specify the maximum line length"
        ])
    <*> modeOption (mconcat [
        long "mode", short 'm', metavar "MODE",
        value PageMode, showDefaultWith $ const "normal",
        help "Specify the rendering mode as either `normal' or `one-line'"
        ])
    <*> option auto (mconcat [
        long "ribbons-per-line", short 'r', metavar "RIBBONS",
        value 1.5, showDefault,
        help "Specify the ratio of line length to ribbon length"
        ])
    <*> strArgument (mconcat [
        metavar "FILE"
        ])
    where
        modeOption = option $ readerAsk >>= \opt -> case opt of
            "normal"    -> return PageMode
            "one-line"  -> return OneLineMode
            _           -> readerError $ "unrecognised mode `" ++ opt ++ "'"


-- ** Helpers

formatOption :: Mod OptionFields Build.Format -> Parser Build.Format
formatOption = option $ readerAsk >>= \opt -> case opt of
    "assembly"  -> return Build.Assembly
    "bitcode"   -> return Build.Bitcode
    _           -> readerError $ "unrecognised format `" ++ opt ++ "'"