unicoder-0.5.0: app/unicoder.hs
import Data.String (IsString(..))
import Data.Default
import Control.Monad
import System.FilePath
import System.Directory
import System.IO
import System.Exit
import System.Console.GetOpt
import System.Environment
import Twitch (Dep, (|>))
import qualified Twitch
import qualified Data.Text.IO as T
import Text.Unicoder
import Paths_unicoder
import Data.Version
main :: IO ()
main = do
opts <- getOptions
m_config <- loadConfig =<< locateConfig (optConfig opts)
config <- case m_config of
Nothing -> die "bad configuration file"
Just config -> return config
case optMode opts of
StdPipes -> runHandle config (stdin, stdout)
InPlace files -> mapM_ (runFile config) files
FileWatch globs ->
Twitch.defaultMainWithOptions def $
forM_ (fromString <$> globs) $ \glob ->
glob |> runFile config
exitSuccess
runFile :: Config -> FilePath -> IO ()
runFile config filename = do
source <- T.readFile filename
let result = unicodize config source
T.writeFile filename result
runHandle :: Config -> (Handle, Handle) -> IO ()
runHandle config (i, o) = do
source <- T.hGetContents i
let result = unicodize config source
T.hPutStr o result
{-| Determine the filesystem location of a config file path.
If the path does not include a slash, then it is resolved using
the unicoder built-in locations. If it does include a slash, then
it is resolved relative to the passed working directory.
-}
locateConfig :: FilePath -- ^ the config path to resolve
-> IO FilePath -- ^ resolved, absolute path to the file
locateConfig path
| pathSeparator `elem` path = do
cwd <- getCurrentDirectory
return $ normalise (cwd </> path)
| otherwise = getDataFileName (path <.> "conf")
putErrLn = hPutStrLn stderr
data Mode
= StdPipes
| InPlace [FilePath]
| FileWatch [String]
deriving (Show)
data Options = Options
{ optConfig :: FilePath
, optOutput :: Maybe FilePath
, optMode :: Mode
}
deriving (Show)
instance Default Options where
def = Options
{ optConfig = "default"
, optOutput = Nothing
, optMode = StdPipes
}
getOptions :: IO Options
getOptions = do
(actions, args, errors) <- getOpt Permute options <$> getArgs
if null errors
then do
opts <- foldl (>>=) (return def) actions
case optMode opts of
InPlace _ -> return $ opts { optMode = InPlace args }
FileWatch _ -> return $ opts { optMode = FileWatch args }
_ | null args -> return opts
| otherwise -> die $ "unrecognized option: " ++ show (head args)
else do
mapM_ putErrLn errors
exitFailure
options :: [OptDescr (Options -> IO Options)]
options =
[ Option "i" ["in-place"]
(NoArg
(\opt -> return opt {optMode = InPlace (error "uninit'd in-place") }))
"Run once on listed files."
, Option "w" ["file-watch"]
(NoArg
(\opt -> return opt { optMode = FileWatch (error "uninit'd file-watch") }))
(unlines [ "Run on files whenever they are changed."
, "Glob syntax is supported (including `**`) so that we can watch for new files."
, "NOTE: Quote glob patterns whenever your shell already supports glob."
])
, Option "c" ["config"]
(ReqArg
(\arg opt -> return opt { optConfig = arg })
"file")
"Specify a configuration (usually a programming language)."
, Option "V" ["version"]
(NoArg
(\_ -> do
putStrLn (showVersion version)
exitSuccess))
"Print version."
, Option "" ["show-config-dir"]
(NoArg
(\_ -> do
putStrLn =<< getDataFileName ""
exitSuccess))
"Print directory where configuration files are stored."
, Option "h" ["help"]
(NoArg
(\_ -> do
prg <- getProgName
putStrLn $ concat ["Unicoder v", showVersion version, "-beta"]
putStrLn "Ease input of unicode glyphs."
putStrLn "This program is lisenced under the 3-clause BSD lisence."
putStrLn (usageInfo (prg ++ " [options] [-i files... | -w globs...]") options)
putStrLn "Replace special sequences of characters (as defined in a config file) with otherwise hard-to-type replacements."
putStrLn "The idea is to make it easy to insert unicode symbols: type an escape sequence and run this tool over the source."
putStrLn "--Config Files"
putStrLn " Configuration files end in `.conf`. Use `--show-config-dir` to see where they are stored."
putStrLn " Passing a file to `-c` that contains a slash will use exactly the file you specify, instead of looking one up."
putStrLn " Check out an installed config file to see the syntax."
putStrLn "--More Info"
putStrLn " For more documentation, go to: http://zankoku-okuno.viewdocs.io/unicoder/"
exitSuccess))
"Show help"
]