summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Blessings.hs96
1 files changed, 90 insertions, 6 deletions
diff --git a/src/Blessings.hs b/src/Blessings.hs
index 559db3e..8b55e24 100644
--- a/src/Blessings.hs
+++ b/src/Blessings.hs
@@ -264,11 +264,95 @@ stripSGR = \case
Empty -> Empty
+normalize' :: (Eq a, Monoid a) => Blessings a -> Blessings a -> Blessings a
+normalize' t t' =
+ if t' == t
+ then t
+ else normalize t'
+
+
+normalize :: (Eq a, Monoid a) => Blessings a -> Blessings a
+normalize = \case
+ Append Empty t -> normalize t
+ Append t Empty -> normalize t
+ Append (Append t1 t2) t3 -> normalize $ Append t1 (Append t2 t3)
+ Append (Plain s1) (Plain s2) -> normalize $ Plain (s1 <> s2)
+
+ Append (Plain s1) (Append (Plain s2) t1) ->
+ normalize (Append (Plain (s1 <> s2)) t1)
+
+ t@(Append t1@(SGR pm1 t11) t2@(Append (SGR pm2 t21) t22)) ->
+ let
+ pm1' = normalizePm pm1
+ pm2' = normalizePm pm2
+ in
+ if pm1' == pm2'
+ then normalize (Append (SGR pm1 (Append t11 t21)) t22)
+ else normalize' t $ Append (normalize t1) (normalize t2)
+
+ t@(Append t1@(SGR pm1 t11) t2@(SGR pm2 t21)) ->
+ let
+ pm1' = normalizePm pm1
+ pm2' = normalizePm pm2
+ in
+ if pm1' == pm2'
+ then normalize (SGR pm1' (Append t11 t21))
+ else normalize' t $ Append (normalize t1) (normalize t2)
+
+ t@(Append t1 t2) -> normalize' t $ Append (normalize t1) (normalize t2)
+ SGR _ Empty -> Empty
+ SGR [] t -> normalize t
+ t@(SGR pm t1) -> normalize' t $ SGR (normalizePm pm) (normalize t1)
+ Plain x | x == mempty -> Empty
+ t@(Plain _) -> t
+ Empty -> Empty
+
+
+data NormalizedPm
+ = NormalizedPm
+ { foregroundColor :: [Word8]
+ , backgroundColor :: [Word8]
+ }
+
+emptyNormalizedPm :: NormalizedPm
+emptyNormalizedPm
+ = NormalizedPm
+ { foregroundColor = []
+ , backgroundColor = []
+ }
+
+normalizePm :: [Word8] -> [Word8]
+normalizePm pm0 =
+ collectEffective emptyNormalizedPm $ skipCanceled pm0 pm0
+ where
+ collectEffective p = \case
+ -- direct-color
+ (38 : 2 : r : g : b : pm) -> collectEffective (p { foregroundColor = [38, 2, r, g, b] }) pm
+ (48 : 2 : r : g : b : pm) -> collectEffective (p { backgroundColor = [48, 2, r, g, b] }) pm
+ -- indexed-color
+ (38 : 5 : i : pm) -> collectEffective (p { foregroundColor = [38, 5, i] }) pm
+ (48 : 5 : i : pm) -> collectEffective (p { backgroundColor = [48, 5, i] }) pm
+ (ps : pm)
+ -- 8-color (must be analyzed after direct- and indexed-colors)
+ | 30 <= ps && ps <= 39 -> collectEffective (p { foregroundColor = [ps] }) pm
+ | 40 <= ps && ps <= 49 -> collectEffective (p { backgroundColor = [ps] }) pm
+ -- ignore everything else
+ | otherwise -> ps : collectEffective p pm
+ [] -> foregroundColor p <> backgroundColor p
+
+ skipCanceled xs = \case
+ (38 : 2 : _ : _ : _ : pm) -> skipCanceled xs pm
+ (38 : 5 : _ : pm) -> skipCanceled xs pm
+ xs'@(0 : pm) -> skipCanceled xs' pm
+ (_ : pm) -> skipCanceled xs pm
+ [] -> xs
+
+
pp :: (Blessable a) => Blessings a -> a
pp t = render emptyRenderState t ""
-instance Blessable a => Blessable (Blessings a) where
+instance (Eq a, Blessable a) => Blessable (Blessings a) where
length (Plain x) = Bless.length x
length (SGR _ t) = Bless.length t
length (Append t1 t2) = Bless.length t1 + Bless.length t2
@@ -287,9 +371,9 @@ instance Blessable a => Blessable (Blessings a) where
then t2'
else Append t1' t2'
Plain s ->
- Plain (Bless.drop n s)
+ normalize $ Plain (Bless.drop n s)
SGR pm t ->
- SGR pm (Bless.drop n t)
+ normalize $ SGR pm (Bless.drop n t)
Empty ->
Empty
@@ -303,15 +387,15 @@ instance Blessable a => Blessable (Blessings a) where
then t1' <> Bless.take n' t2
else t1'
Plain s ->
- Plain (Bless.take n s)
+ normalize $ Plain (Bless.take n s)
SGR pm t ->
- SGR pm (Bless.take n t)
+ normalize $ SGR pm (Bless.take n t)
Empty ->
Empty
intercalate i = \case
[] -> mempty
[t] -> t
- (t:ts) -> t <> i <> Bless.intercalate i ts
+ (t:ts) -> normalize $ t <> i <> Bless.intercalate i ts
fromWord8 = Plain . Bless.fromWord8