Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate hex colors in FromJSON instance #2237

Merged
merged 5 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- {name: Prelude.!!, within: [Swarm.Util.indexWrapNonEmpty, TestEval]}
- {name: undefined, within: [Swarm.Language.Key, TestUtil]}
- {name: fromJust, within: []}
- {name: Data.Colour.SRGB.sRGB24read, within: []}
# - {name: Data.Map.!, within: []} # TODO: #1494
# - {name: error, within: []} # TODO: #1494

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 1
name: Custom attribute - invalid color
description: |
Invalid color in custom attribute
creative: false
attrs:
- name: bogus
bg: "this is not a color"
terrains:
- name: whatzit
attr: bogus
description: |
A thingy
robots:
- name: base
dir: east
world:
dsl: |
{grass}
palette:
'B': [grass, null, base]
'.': [whatzit]
upperleft: [0, 0]
map: |
B.
46 changes: 32 additions & 14 deletions src/swarm-scenario/Swarm/Game/Scenario/Style.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
Expand All @@ -7,9 +9,9 @@ module Swarm.Game.Scenario.Style where
import Codec.Picture (PixelRGBA8 (..))
import Data.Aeson
import Data.Colour.Palette.Types (Kolor)
import Data.Colour.SRGB (RGB (..), sRGB24read, toSRGB24)
import Data.Colour.SRGB (RGB (..), sRGB24reads, sRGB24show, toSRGB24)
import Data.Colour.SRGB.Linear (toRGB)
import Data.Set (Set)
import Data.Text (Text)
import Data.Text qualified as T
import GHC.Generics (Generic)
import Swarm.Game.Entity.Cosmetic
Expand Down Expand Up @@ -38,17 +40,36 @@ instance FromJSON StyleFlag where
instance ToJSON StyleFlag where
toJSON = genericToJSON styleFlagJsonOptions

-- | Hexadecimal color notation.
-- May include a leading hash symbol (see 'Data.Colour.SRGB.sRGB24read').
newtype HexColor = HexColor Text
deriving (Eq, Ord, Show, Generic, FromJSON, ToJSON)
-- | A color, parsed from hexadecimal notation. May include a leading
-- hash symbol (see 'Data.Colour.SRGB.sRGB24read').
newtype HexColor = HexColor {getHexColor :: Kolor}
deriving (Eq, Show, Generic)

instance Ord HexColor where
-- There is no Ord instance for Colour a, but we need one to use
-- with OccurrenceEncoder, so we make our own.
--
-- We use toRGB here since it does no conversions whatsoever, it
-- simply unpacks the raw color data into an RGB triple. For the
-- purposes of an Ord instance, it doesn't matter: we just want a
-- consistent way to put a total ordering on colors as fast as
-- possible.
compare (HexColor (toRGB -> RGB r1 g1 b1)) (HexColor (toRGB -> RGB r2 g2 b2)) =
compare (r1, g1, b1) (r2, g2, b2)

instance FromJSON HexColor where
parseJSON = withText "hex color" $ \t ->
case sRGB24reads (T.unpack t) of
((c, _) : _) -> pure $ HexColor c
_ -> fail $ "Could not parse hex color '" ++ T.unpack t ++ "'"

instance ToJSON HexColor where
toJSON = toJSON . T.pack . sRGB24show . getHexColor

instance ToPixel HexColor where
toPixel (HexColor colorText) = PixelRGBA8 r g b 255
toPixel (HexColor kolor) = PixelRGBA8 r g b 255
where
temp :: Kolor
temp = sRGB24read $ T.unpack colorText
byorgey marked this conversation as resolved.
Show resolved Hide resolved
RGB r g b = toSRGB24 temp
RGB r g b = toSRGB24 kolor

data CustomAttr = CustomAttr
{ name :: String
Expand Down Expand Up @@ -77,7 +98,4 @@ toHifiPair (CustomAttr n maybeFg maybeBg _) =
(Nothing, Just b) -> Just $ BgOnly b
(Nothing, Nothing) -> Nothing

conv (HexColor x) = Triple $ toSRGB24 kolor
where
kolor :: Kolor
kolor = sRGB24read $ T.unpack x
conv (HexColor kolor) = Triple $ toSRGB24 kolor
7 changes: 1 addition & 6 deletions src/swarm-tui/Swarm/TUI/View/Attribute/CustomStyling.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
-- SPDX-License-Identifier: BSD-3-Clause
module Swarm.TUI.View.Attribute.CustomStyling where

import Data.Colour.SRGB (sRGB24read)
import Data.Set (toList)
import Data.Text qualified as T
import Graphics.Vty.Attributes
import Swarm.Game.Entity.Cosmetic (WorldAttr (..))
import Swarm.Game.Scenario.Style
Expand All @@ -22,10 +20,7 @@ toStyle = \case
Bold -> bold

hexToAttrColor :: HexColor -> Color
hexToAttrColor (HexColor colorText) =
kolorToAttrColor c
where
c = sRGB24read $ T.unpack colorText
hexToAttrColor (HexColor kolor) = kolorToAttrColor kolor

toAttrPair :: CustomAttr -> (WorldAttr, Attr)
toAttrPair ca =
Expand Down
5 changes: 2 additions & 3 deletions src/swarm-web/Swarm/Web/Worldview.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ module Swarm.Web.Worldview where
import Control.Lens ((^.))
import Data.Aeson (ToJSON)
import Data.Colour.Palette.BrewerSet (Kolor)
import Data.Colour.SRGB (RGB (..), sRGB24, sRGB24show)
import Data.Colour.SRGB (RGB (..), sRGB24)
import Data.IntMap qualified as IM
import Data.Text qualified as T
import GHC.Generics (Generic)
import Servant.Docs qualified as SD
import Swarm.Game.Entity.Cosmetic (RGBColor, flattenBg, fromHiFi)
Expand Down Expand Up @@ -44,7 +43,7 @@ getCellGrid myScenario gs requestedSize =

asColour :: RGBColor -> Kolor
asColour (RGB r g b) = sRGB24 r g b
asHex = HexColor . T.pack . sRGB24show . asColour
asHex = HexColor . asColour

f = asHex . maybe (RGB 0 0 0) (flattenBg . fromHiFi) . getTerrainEntityColor aMap
(indexGrid, encoding) = runEncoder $ f <$> dg
Expand Down
Loading