packages feed

alea-0.5.2.0: src/Main.hs

{-# LANGUAGE RecordWildCards #-}
-- | Main module
module Main where

import Control.Monad             (when, forever)
import Data.Text                 (unpack)
import Data.Monoid
import Options.Applicative
import Alea.Diceware
import Paths_alea                (getDataFileName)

import qualified Data.Text    as T
import qualified Data.Text.IO as I


-- * Command line interface description

-- | Program arguments record
data Options = Options
  { interactive  :: Bool
  , dictionary   :: Maybe FilePath
  , phraseLength :: Int
  , phrases      :: Int
  }


-- | Argument parser 
options :: Parser Options
options = Options 
  <$> switch
      ( long "interactive"
     <> short 'i'
     <> help "Manually insert numbers from a dice" )
  <*> optional (option auto
      ( long "dictionary"
     <> short 'd'
     <> metavar "FILEPATH"
     <> help "Specify dictionary filepath" ))
  <*> option auto
      ( long "length"
     <> short 'l'
     <> value 6
     <> metavar "N"
     <> help "Number of words in a passphrase")
  <*> option auto
     ( long "phrases"
    <> short 'p'
    <> value 1
    <> metavar "M"
    <> help "Number of passphrases to generate" )
  

-- | Program description
description :: ParserInfo Options
description = info (helper <*> options)
  ( fullDesc
 <> progDesc "A diceware passphrase generator"
 <> footer "Alea iacta est." )



-- * Program

-- | Main function
main :: IO ()
main = execParser description >>= diceware


-- | Actual application 
diceware :: Options -> IO ()
diceware opts@Options{..} = do
  path <- case dictionary of
    Nothing -> getDataFileName "dict/diceware"
    Just x  -> return x
  dict <- parseDiceware <$> I.readFile path
  let size  = length dict-1
      dice  = readDiceware  dict . read . unpack
      dice' = readDiceware' dict

  if interactive
    then forever (dice <$> I.getLine >>= I.putStrLn)
    else do
      indices <- randIndices size phraseLength
      I.putStrLn $ T.unwords (map dice' indices)
      when (phrases > 1) $
        diceware opts {phrases = phrases - 1}