packages feed

Tablify-0.8: src/Tablify.hs

-- Generates tables from CSV files.
--
-- I wrote it specifically to make pretty Unicode tables like this:
-- 
-- ┌─────┬─────┬─────┐
-- │ foo │ bar │ baz │
-- ├─────┼─────┼─────┤
-- │ boo │ baa │ bee │
-- │ haa │ hee │ hoo │
-- └─────┴─────┴─────┘
--
-- It always treats the first record as the column headers.

module Main where

-- this declaration lets me forget all about qualifying the UTF8 version of IO
--import Prelude hiding (putStr, putStrLn, getContents) 

import System
import System.IO
--import System.IO.SaferFileHandles
--import System.IO.UTF8
import System.Console.GetOpt

import Converter
import Utilities
import Unicode
import HTML
import TBL
import ASCII
import CSV
import LaTeX

version :: Double
version = 0.8

data Options = Options 
    { optHelp        :: Bool
    , optVersion     :: Bool
    , optConverter   :: Converter
    }

defaultOptions :: Options
defaultOptions = Options
    { optHelp      = False
    , optVersion   = False
    , optConverter = HTML.converter
    }

converters :: [Converter]
converters = 
    [ ASCII.converter
    , HTML.converter
    , TBL.converter
    , Unicode.converter
    , LaTeX.converter]

usage :: String
usage = "Usage: tablify [OPTION...] file"

options :: [OptDescr (Options -> Options)]
options = 
    [ Option "v"  ["version"] 
        (NoArg (\o -> o { optVersion = True }))
        "show version"
    , Option "h"  ["help"] 
        (NoArg (\o -> o { optHelp = True }))
        "show this help" ] ++ moreOptions
    where
        moreOptions = map converterToOption converters
        converterToOption c@(Converter name _ short long) = 
            Option short [long] 
                (NoArg (\o -> o {optConverter = c}))
                ("output " ++ name ++ " table")

getOptions :: [String] -> IO (Options, [String])
getOptions argv =
    case getOpt Permute options argv of
        (o, n, []) -> return (foldl (flip id) defaultOptions o, n)
        (_, _, errors) -> ioError (userError 
                            (concat errors ++ usageInfo usage options))

processOpts :: Table -> Options -> String
processOpts table (Options _ _ (Converter { cConvert = f })) = f table
        
parseData :: String -> IO Table
parseData dat = case parseCSV dat of 
    Left _ -> ioError $ userError "unable to parse file"
    Right result -> return result

processFile :: Options -> String -> IO ()
processFile opts file = do
    fileData <- if file == "-" then getContents    else readFile file
    table <- parseData fileData
    putStrLn $ processOpts table opts

showInfo :: Options -> IO ()
showInfo Options { optVersion = True } = putStrLn $ "tablify version " ++ show version
showInfo Options { optHelp = True }    = putStr $ usageInfo usage options
showInfo _                             = fail "unable to show info for weird options"

main :: IO ()
main = do
    args <- getArgs
    (opts, arguments) <- getOptions args
    hSetEncoding stdout utf8
    if optHelp opts || optVersion opts 
        then showInfo opts
        else mapM_ (processFile opts) arguments