fix(xanthous): Only use alphabetic chars for menu items

Previously, we were using `smallestNotIn` for selecting new characters
for menu items with duplicate chatacters - this uses the 'Bounded'
instance for the type, which for Char meant the first character we would
always select was \NUL - making it look like the menu item had no
character, and making it impossible to actually select the menu item.
This introduces an AlphaChar newtype, which is a wrapper around Char
whose Bounded and Enum instances only use alphabetic characters (a-ZA-Z)
and uses that for menu characters instead.

Change-Id: If34ed9e9ce84f2bcb1cb87432cc6273f40b69f72
Reviewed-on: https://cl.tvl.fyi/c/depot/+/3229
Reviewed-by: grfn <grfn@gws.fyi>
Tested-by: BuildkiteCI
This commit is contained in:
Griffin Smith 2021-06-20 16:44:12 -04:00 committed by grfn
parent 76258fbfa1
commit 7437a18188
6 changed files with 63 additions and 3 deletions

View file

@ -38,6 +38,9 @@ module Xanthous.Util
-- * Type-level programming utils
, KnownBool(..)
-- *
, AlphaChar(..)
) where
--------------------------------------------------------------------------------
import Xanthous.Prelude hiding (foldr)
@ -299,3 +302,34 @@ modifyK k = get >>= k >>= put
-- @@
modifyKL :: MonadState s m => LensLike m s s a b -> (a -> m b) -> m ()
modifyKL l k = get >>= traverseOf l k >>= put
--------------------------------------------------------------------------------
-- | A newtype wrapper around 'Char' whose 'Enum' and 'Bounded' instances only
-- include the characters @[a-zA-Z]@
--
-- >>> succ (AlphaChar 'z')
-- 'A'
newtype AlphaChar = AlphaChar { getAlphaChar :: Char }
deriving stock Show
deriving (Eq, Ord) via Char
instance Enum AlphaChar where
toEnum n
| between 0 25 n
= AlphaChar . toEnum $ n + fromEnum 'a'
| between 26 51 n
= AlphaChar . toEnum $ n - 26 + fromEnum 'A'
| otherwise
= error $ "Tag " <> show n <> " out of range [0, 51] for enum AlphaChar"
fromEnum (AlphaChar chr)
| between 'a' 'z' chr
= fromEnum chr - fromEnum 'a'
| between 'A' 'Z' chr
= fromEnum chr - fromEnum 'A'
| otherwise
= error $ "Invalid value for alpha char: " <> show chr
instance Bounded AlphaChar where
minBound = AlphaChar 'a'
maxBound = AlphaChar 'Z'