diff options
-rw-r--r-- | src/Command.hs | 7 | ||||
-rw-r--r-- | src/Main.hs | 62 | ||||
-rw-r--r-- | src/Types.hs | 4 | ||||
-rw-r--r-- | src/Utils.hs | 20 |
4 files changed, 71 insertions, 22 deletions
diff --git a/src/Command.hs b/src/Command.hs index 659d14d..127e986 100644 --- a/src/Command.hs +++ b/src/Command.hs | |||
@@ -19,6 +19,9 @@ import qualified Data.Text as Text | |||
19 | 19 | ||
20 | import Data.Maybe (fromMaybe) | 20 | import Data.Maybe (fromMaybe) |
21 | 21 | ||
22 | import Data.CaseInsensitive ( CI ) | ||
23 | import qualified Data.CaseInsensitive as CI | ||
24 | |||
22 | import Types | 25 | import Types |
23 | 26 | ||
24 | data Cmd = PerformAlt Alteration Comment | 27 | data Cmd = PerformAlt Alteration Comment |
@@ -85,7 +88,7 @@ parseCmd' args = do | |||
85 | 88 | ||
86 | cmdParser :: Maybe Entity -> Parser Cmd | 89 | cmdParser :: Maybe Entity -> Parser Cmd |
87 | cmdParser tip = hsubparser $ mconcat [ command "quit" $ pure Quit `info` progDesc "Exit gracefully" | 90 | cmdParser tip = hsubparser $ mconcat [ command "quit" $ pure Quit `info` progDesc "Exit gracefully" |
88 | , command "dump" $ pure Dump `info` progDesc "Print all internal state in a format not necessarily human readable" | 91 | , command "list" $ pure Dump `info` progDesc "Print a list of tracked entities" |
89 | , command "history" $ parseHistory `info` progDesc "Print an excerpt of combat history" | 92 | , command "history" $ parseHistory `info` progDesc "Print an excerpt of combat history" |
90 | , command "who" $ pure ShowTip `info` progDesc "Who’s turn is it?" | 93 | , command "who" $ pure ShowTip `info` progDesc "Who’s turn is it?" |
91 | , command "set" $ parseOverride `info` progDesc "Set an entities sequence value" | 94 | , command "set" $ parseOverride `info` progDesc "Set an entities sequence value" |
@@ -116,7 +119,7 @@ cmdParser tip = hsubparser $ mconcat [ command "quit" $ pure Quit `info` progDes | |||
116 | entity | 119 | entity |
117 | | (Just tip') <- tip = fromMaybe tip' <$> optional entity' | 120 | | (Just tip') <- tip = fromMaybe tip' <$> optional entity' |
118 | | otherwise = entity' | 121 | | otherwise = entity' |
119 | entity' = Entity <$> (Text.pack <$> strArgument (help "Name of the target entity" <> metavar "NAME")) <*> optional (argument positive $ help "Number of the target entity" <> metavar "NUMBER") | 122 | entity' = Entity <$> (CI.mk . Text.pack <$> strArgument (help "Name of the target entity" <> metavar "NAME")) <*> optional (option positive $ long "number" <> short 'n' <> help "Number of the target entity" <> metavar "NUMBER") |
120 | 123 | ||
121 | sequenceValue = argument auto (help "Sequence value adjustment" <> metavar "SEQUENCE") | 124 | sequenceValue = argument auto (help "Sequence value adjustment" <> metavar "SEQUENCE") |
122 | sequenceValue' = argument auto (help "Sequence value" <> metavar "SEQUENCE") | 125 | sequenceValue' = argument auto (help "Sequence value" <> metavar "SEQUENCE") |
diff --git a/src/Main.hs b/src/Main.hs index 86c8771..4429853 100644 --- a/src/Main.hs +++ b/src/Main.hs | |||
@@ -1,4 +1,4 @@ | |||
1 | {-# LANGUAGE FlexibleContexts, ViewPatterns, OverloadedStrings #-} | 1 | {-# LANGUAGE FlexibleContexts, ViewPatterns, OverloadedStrings, TupleSections #-} |
2 | 2 | ||
3 | import Data.PQueue.Prio.Max (MaxPQueue) | 3 | import Data.PQueue.Prio.Max (MaxPQueue) |
4 | import qualified Data.PQueue.Prio.Max as MaxPQueue | 4 | import qualified Data.PQueue.Prio.Max as MaxPQueue |
@@ -9,8 +9,11 @@ import qualified Data.Sequence as Seq | |||
9 | import Data.Text (Text) | 9 | import Data.Text (Text) |
10 | import qualified Data.Text as Text | 10 | import qualified Data.Text as Text |
11 | 11 | ||
12 | import Data.Set (Set) | ||
13 | import qualified Data.Set as Set | ||
14 | |||
12 | import Data.Default.Class | 15 | import Data.Default.Class |
13 | import Data.Maybe (fromMaybe) | 16 | import Data.Maybe (fromMaybe, isNothing, fromJust) |
14 | 17 | ||
15 | import System.Environment.XDG.BaseDir (getUserCacheFile) | 18 | import System.Environment.XDG.BaseDir (getUserCacheFile) |
16 | import System.Environment (getProgName) | 19 | import System.Environment (getProgName) |
@@ -54,7 +57,7 @@ runCli = do | |||
54 | 57 | ||
55 | Quit -> liftIO exitSuccess | 58 | Quit -> liftIO exitSuccess |
56 | 59 | ||
57 | Dump -> get >>= outputStrLn . show | 60 | Dump -> gets ctxSequence >>= mapM_ (outputStrLn . showAssoc) . MaxPQueue.toDescList |
58 | ShowTip -> do | 61 | ShowTip -> do |
59 | tip <- fmap snd <$> gets (MaxPQueue.getMax . ctxSequence) | 62 | tip <- fmap snd <$> gets (MaxPQueue.getMax . ctxSequence) |
60 | case tip of | 63 | case tip of |
@@ -63,6 +66,57 @@ runCli = do | |||
63 | ShowHistory ns -> do | 66 | ShowHistory ns -> do |
64 | let sel = maybe id takeR ns | 67 | let sel = maybe id takeR ns |
65 | mapM_ (outputStrLn . show) =<< sel <$> gets ctxHistory | 68 | mapM_ (outputStrLn . show) =<< sel <$> gets ctxHistory |
66 | PerformAlt alt comment -> apply' alt comment | 69 | PerformAlt alt comment -> apply alt comment |
67 | _ -> undefined | 70 | _ -> undefined |
68 | runCli | 71 | runCli |
72 | |||
73 | showAssoc :: (SequenceValue, Entity) -> String | ||
74 | showAssoc (val, entity) = show val <> "\t" <> (Text.unpack $ showEntity entity) | ||
75 | |||
76 | |||
77 | apply :: SequenceM m => Alteration -> Comment -> InputT m () | ||
78 | apply alteration comment = alter alteration >> modify (\ctx -> ctx { ctxHistory = ctxHistory ctx |> (alteration, comment) }) | ||
79 | |||
80 | alter :: SequenceM m => Alteration -> InputT m () | ||
81 | alter (Modify entity ((+) -> mod)) = alterMatching entity mod | ||
82 | alter (Override entity (const -> mod)) = alterMatching entity mod | ||
83 | alter (Rename old new) = do | ||
84 | [(k, _)] <- filter (\(_, v) -> v == old) <$> gets (MaxPQueue.assocsU . ctxSequence) | ||
85 | alter (Drop old) | ||
86 | alter (Insert new k) | ||
87 | alter (Drop entity) = do | ||
88 | (matching, notMatching) <- MaxPQueue.partition (== entity) <$> gets ctxSequence | ||
89 | modify $ \ctx -> ctx { ctxSequence = notMatching } | ||
90 | when (MaxPQueue.null matching) warnEmpty | ||
91 | alter (Insert entity val) = do | ||
92 | modify $ \ctx -> ctx { ctxSequence = MaxPQueue.insert val entity $ ctxSequence ctx } | ||
93 | introduceNumbering entity | ||
94 | |||
95 | |||
96 | alterMatching :: SequenceM m => Entity -> (SequenceValue -> SequenceValue) -> InputT m () | ||
97 | alterMatching entity mod = do | ||
98 | (matching, notMatching) <- MaxPQueue.partition (== entity) <$> gets ctxSequence | ||
99 | modify $ \ctx -> ctx { ctxSequence = notMatching `MaxPQueue.union` MaxPQueue.mapKeys mod matching } | ||
100 | when (MaxPQueue.null matching) warnEmpty | ||
101 | |||
102 | introduceNumbering :: SequenceM m => Entity -> InputT m () | ||
103 | introduceNumbering entity = do | ||
104 | let | ||
105 | matches (Entity name _) (Entity name' _) = name == name' | ||
106 | (matching, notMatching) <- MaxPQueue.partition (matches entity) <$> gets ctxSequence | ||
107 | if MaxPQueue.size matching <= 1 | ||
108 | then return () | ||
109 | else do | ||
110 | let | ||
111 | (matching', notMatching') = MaxPQueue.partition (\(Entity _ n) -> isNothing n) matching | ||
112 | maxN = MaxPQueue.foldrU (\(Entity _ n) -> max n) (Just 0) notMatching' | ||
113 | modify $ \ctx -> ctx { ctxSequence = snd $ MaxPQueue.foldrWithKey accum (fromJust maxN, MaxPQueue.union notMatching notMatching') matching' } | ||
114 | if MaxPQueue.null notMatching' | ||
115 | then outputStrLn $ "Had to introduce a numbering scheme to differentiate multiple entities called »" <> (Text.unpack $ showEntity entity) <> "«" | ||
116 | else outputStrLn $ "Inserted new entity called »" <> (Text.unpack $ showEntity entity) <> "« into existing numbering scheme" | ||
117 | where | ||
118 | accum key (Entity val _) (n, queue) = (succ n, MaxPQueue.insert key (Entity val $ Just (succ n)) queue) | ||
119 | |||
120 | warnEmpty :: MonadIO m => InputT m () | ||
121 | warnEmpty = outputStrLn "Selection did not match any entities" | ||
122 | |||
diff --git a/src/Types.hs b/src/Types.hs index a90e5fe..031d2d5 100644 --- a/src/Types.hs +++ b/src/Types.hs | |||
@@ -22,6 +22,8 @@ import Data.Text (Text) | |||
22 | 22 | ||
23 | import Data.Default.Class | 23 | import Data.Default.Class |
24 | 24 | ||
25 | import Data.CaseInsensitive (CI) | ||
26 | |||
25 | import Control.Monad.State.Strict (MonadState(..), MonadTrans(..)) | 27 | import Control.Monad.State.Strict (MonadState(..), MonadTrans(..)) |
26 | import Control.Monad.Writer.Strict (MonadWriter, MonadTrans(..)) | 28 | import Control.Monad.Writer.Strict (MonadWriter, MonadTrans(..)) |
27 | 29 | ||
@@ -30,7 +32,7 @@ import Control.Monad.IO.Class (MonadIO) | |||
30 | import System.Console.Haskeline (InputT) | 32 | import System.Console.Haskeline (InputT) |
31 | 33 | ||
32 | 34 | ||
33 | data Entity = Entity Text (Maybe Integer) | 35 | data Entity = Entity (CI Text) (Maybe Integer) |
34 | deriving (Eq, Ord, Show) | 36 | deriving (Eq, Ord, Show) |
35 | 37 | ||
36 | type SequenceValue = Integer | 38 | type SequenceValue = Integer |
diff --git a/src/Utils.hs b/src/Utils.hs index cac88ac..b98359a 100644 --- a/src/Utils.hs +++ b/src/Utils.hs | |||
@@ -2,8 +2,6 @@ | |||
2 | 2 | ||
3 | module Utils | 3 | module Utils |
4 | ( showEntity | 4 | ( showEntity |
5 | , apply, apply' | ||
6 | , entities | ||
7 | , takeR | 5 | , takeR |
8 | ) where | 6 | ) where |
9 | 7 | ||
@@ -24,23 +22,15 @@ import qualified Data.Set as Set | |||
24 | import Data.Sequence (Seq, ViewR(..), (|>)) | 22 | import Data.Sequence (Seq, ViewR(..), (|>)) |
25 | import qualified Data.Sequence as Seq | 23 | import qualified Data.Sequence as Seq |
26 | 24 | ||
25 | import Data.CaseInsensitive ( CI ) | ||
26 | import qualified Data.CaseInsensitive as CI | ||
27 | |||
27 | import Types | 28 | import Types |
28 | 29 | ||
29 | showEntity :: Entity -> Text | 30 | showEntity :: Entity -> Text |
30 | showEntity (Entity name number) | 31 | showEntity (Entity name number) |
31 | | (Just (show -> n)) <- number = name <> " № " <> Text.pack n | 32 | | (Just (show -> n)) <- number = CI.original name <> " № " <> Text.pack n |
32 | | otherwise = name | 33 | | otherwise = CI.original name |
33 | |||
34 | apply' :: MonadState Context m => Alteration -> Comment -> m () | ||
35 | apply' alteration comment = modify $ onCtx (apply alteration comment) | ||
36 | where | ||
37 | onCtx f ctx = let (sequence', history') = f $ ctxSequence ctx in ctx { ctxSequence = sequence', ctxHistory = ctxHistory ctx <> history' } | ||
38 | |||
39 | apply :: Alteration -> Comment -> Sequence -> (Sequence, History) | ||
40 | apply alteration comment seq = undefined | ||
41 | |||
42 | entities :: MonadState Sequence m => m (Set Entity) | ||
43 | entities = Set.fromList . MaxPQueue.elems <$> get | ||
44 | 34 | ||
45 | takeR :: Integer -> Seq a -> Seq a | 35 | takeR :: Integer -> Seq a -> Seq a |
46 | takeR _ (Seq.viewr -> EmptyR) = Seq.empty | 36 | takeR _ (Seq.viewr -> EmptyR) = Seq.empty |