Main.hs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE OverloadedLists #-}
  3. {-# LANGUAGE TypeFamilies #-}
  4. module Main where
  5. import qualified Control.Exception as Exn
  6. import qualified Control.Monad as M
  7. import qualified Data.IORef as IO
  8. import qualified Data.Map.Strict as Map
  9. import Data.Monoid ((<>))
  10. import qualified Data.Text as Text
  11. import qualified Data.Text.IO as Text
  12. import qualified System.Console.Readline as Readline
  13. import qualified System.Environment as Env
  14. import qualified System.Exit as Exit
  15. import qualified Parser
  16. import qualified Types
  17. readMap :: FilePath -> IO Types.TableMap
  18. readMap path = do
  19. cs <- Text.readFile path
  20. pure $ Map.fromList
  21. [ (Types.tableName t, t)
  22. | t <- Parser.parseTable cs
  23. ]
  24. main :: IO ()
  25. main = do
  26. args <- Env.getArgs
  27. let filename = case args of
  28. path:_ -> path
  29. _ -> "perilous-wilds.txt"
  30. tablesRef <- IO.newIORef =<< readMap filename
  31. Readline.setCompletionEntryFunction $ Just $ \ rs -> do
  32. tables <- IO.readIORef tablesRef
  33. pure [ Text.unpack k
  34. | k <- Map.keys tables
  35. , Text.pack rs `Text.isPrefixOf` k
  36. ]
  37. M.forever $ do
  38. input <- Readline.readline "\x1b[31m--> \x1b[39m"
  39. case input of
  40. Nothing -> do
  41. putStrLn "farewell"
  42. Exit.exitSuccess
  43. Just ":q" -> do
  44. putStrLn "farewell"
  45. Exit.exitSuccess
  46. Just "" -> pure ()
  47. Just ":l" -> do
  48. tables <- IO.readIORef tablesRef
  49. Text.putStrLn "Available tables: "
  50. Text.putStrLn (" " <> Text.unwords (Map.keys tables))
  51. Just ":r" ->
  52. IO.writeIORef tablesRef =<< readMap filename
  53. Just choice -> do
  54. tables <- IO.readIORef tablesRef
  55. let names = Text.unwords (Map.keys tables)
  56. Readline.addHistory choice
  57. case Map.lookup (Text.strip (Text.pack choice)) tables of
  58. Nothing -> do
  59. Text.putStrLn ("table not found: " <> Text.pack (show choice))
  60. Text.putStrLn (" valid tables include: " <> names)
  61. Just t ->
  62. (Types.rollTable tables t >>= showValueAndRolls)
  63. `Exn.catch` handleBadTable
  64. handleBadTable :: Types.BadTable -> IO ()
  65. handleBadTable bt = do
  66. let msg = Text.intercalate "\n" (Types.potreroMessage bt)
  67. Text.putStr "\x1b[91m"
  68. Text.putStr msg
  69. Text.putStrLn "\x1b[39m"
  70. -- | simply show the value generated
  71. showValue :: Types.Value -> IO ()
  72. showValue value = Text.putStrLn (Types.valueMsg value)
  73. -- | pretty-print the value as well as each roll that was done on an
  74. -- intermediate table
  75. showValueAndRolls :: Types.Value -> IO ()
  76. showValueAndRolls value = go 0 value
  77. where
  78. go n v
  79. | Text.null (Text.strip (Types.valueMsg v)) = pure ()
  80. | otherwise = do
  81. Text.putStr "\x1b[36m"
  82. Text.putStr (Text.replicate (n+1) " ")
  83. putStr (show (Types.valueResult v))
  84. Text.putStr " on "
  85. Text.putStr (Types.valueFrom v)
  86. M.when (null (Types.valueSources v)) $ do
  87. Text.putStr ": \""
  88. Text.putStr (Text.strip (Types.valueMsg v))
  89. Text.putStr "\""
  90. Text.putStrLn "\x1b[39m"
  91. mapM_ (go (n+1)) (Types.valueSources v)
  92. M.when (n == 0) $
  93. Text.putStrLn (Types.valueMsg v)